Java+Opencv 入門彙總

工作需要,用到Java來圖像處理,寫了一手好的matlab,但工作需要就用java+opencv。然而相關資料很少,自己也就想收集一些,供大家參考,會加入一些C++與java的對比。沒有歸類,知道多少就貼多少,看上去有點亂,望見諒。

以下是我找到的一個OpenCV的Java教程文檔!鏈接
opencv發的帖子,有問題請留言

類似以下這樣的知識點,可以留言!!

基本操作,java版opencv跟C++版很類似。差別就是在調用函數前面加入類似Highgui.這樣的庫名。

Mat img=Highgui.imread(路徑); //讀圖像跟C++一樣只是多了Highgui.。
Highgui.imwrite(路徑,img);//寫圖像
Mat img2=new Mat();
Imgproc.blur(img,img2,new Size(3,3));//光滑處理 多了Imgproc.
Imgproc.cvtColor(img,img2,Imgproc.COLOR_BGR2GRAY);//RGB==>Gray
Imgproc.equalizeHist(GrayImg,GrayImg);  //直方圖均衡化   
List<Mat> images = new ArrayList<Mat>();
Core.split(img, images);//RGB通道分離 多了Core.
Mat mat=images.get(2);//獲得第二通道分量
Core.merge(images,img);//RGB通道合併

//Java一維數組給Mat賦值 和從Mat中提取像素值保存在一維數組中        
float data[] = {1,1,1,2,2,2,3,3,3,4,4,4,5,5,5,6,6,6,7,7,7,8,8,8};
Mat mat_gray=new Mat(4,6,CvType.CV_32FC1);
Mat mat_color=new Mat(2,4,CvType.CV_32FC3);
mat_gray.put(0,0,data);//通過一維數組給灰度圖像賦值
mat_color.put(0,0,data);//通過一維數組給彩色圖像賦值
float data2[]=new float[mat_color.rows()*mat_color.cols()*mat_color.channels()];
mat_color.get(0,0,data2);//把mat_color中的像素值保存在一維數組中。且以爲數組的類型必須跟圖像數據類型CvType一致,且數組的大小得確定大於等於行數*列數*通道數。
//需要注意的是,java中Mat對數據類型很敏感。具體問題具體嘗試
/****************************************************
CV_32F  float
CV_16S  short
CV_8S   char   byte     
CV_8U - 8-bit unsigned integers ( 0..255 )    uchar
CV_8S - 8-bit signed integers ( -128..127 )   byte(java) 
CV_16U - 16-bit unsigned integers ( 0..65535 )
CV_16S - 16-bit signed integers ( -32768..32767 )
CV_32S - 32-bit signed integers ( -2147483648..2147483647 )
CV_32F - 32-bit floating-point numbers ( -FLT_MAX..FLT_MAX, INF, NAN )
CV_64F - 64-bit floating-point numbers ( -DBL_MAX..DBL_MAX, INF, NAN )
***************************************************/

//C++一維數組給Mat賦值和從Mat中提取像素值    
float data[24]={1,1,1,2,2,2,3,3,3,4,4,4,5,5,5,6,6,6,7,7,7,8,8,8};
Mat mat_gray=Mat(4,6,CvType.CV_32FC1,data);
Mat mat_color=Mat(2,4,CvType.CV_32FC3,data);
mat_gray.convertTo(mat_gray,CvType.CV_8UC3);
uchar *p=mat_gray.data;//數據指向p指針,就可以通過P指針獲得像素值。前提是p爲 uchar*型。且Mat中數據是順序存儲的。可用isContinuous()函數來判斷。
for(int i=0;i<mat.cols*mat.rows*mat.channels();++i)
{
    printf("%d ",*p++);
}

背景去除 簡單案列,只適合背景單一的圖像

 private Mat doBackgroundRemoval(Mat frame)
 {
  // init
    Mat hsvImg = new Mat();
    List<Mat> hsvPlanes = new ArrayList<>();
    Mat thresholdImg = new Mat();
    int thresh_type = Imgproc.THRESH_BINARY_INV;
// threshold the image with the average hue value
    hsvImg.create(frame.size(), CvType.CV_8U);
    Imgproc.cvtColor(frame, hsvImg,
    Imgproc.COLOR_BGR2HSV);
    Core.split(hsvImg, hsvPlanes);

    // get the average hue value of the image
    Scalar average=Core.mean(hsvPlanes.get(0));
    double threshValue =average.val[0];
    Imgproc.threshold(hsvPlanes.get(0), thresholdImg, threshValue, 179.0, thresh_type);
    Imgproc.blur(thresholdImg, thresholdImg, new Size(5, 5));
    // dilate to fill gaps, erode to smooth edges
    Imgproc.dilate(thresholdImg, thresholdImg, new Mat(), new Point(-1, -1), 1);
    Imgproc.erode(thresholdImg, thresholdImg, new Mat(), new Point(-1, -1), 3);
    Imgproc.threshold(thresholdImg, thresholdImg, threshValue, 179.0, Imgproc.THRESH_BINARY);
    // create the new image
    Mat foreground = new Mat(frame.size(), CvType.CV_8UC3, new Scalar(255, 255, 255));        thresholdImg.convertTo(thresholdImg,CvType.CV_8U);
 frame.copyTo(foreground, thresholdImg);//掩膜圖像複製
 return foreground;
 }

背景去除

人臉檢測

Mat img=讀入圖像
Rect Roi=new Rect(new Point(5,5),new Size(400,800));
Mat image= img.submat(Roi);//子圖
String xmlfilePath = "haarcascade_frontalface_alt2.xml";
MatOfRect faceDetections = new MatOfRect();
CascadeClassifier faceDetector = new CascadeClassifier(xmlfilePath);
faceDetector.detectMultiScale(image , faceDetections, 1.1,2,0|Objdetect.CASCADE_FIND_BIGGEST_OBJECT, new Size( ), new Size());
faceCascade.detectMultiScale(image, faces, 1.1, 2, 0 | Objdetect.CASCADE_SCALE_IMAGE, new Size(), new Size());

//以下是人臉檢測小函數   
private void detectAndDisplay(Mat frame)
{
    MatOfRect faces = new MatOfRect();
    Mat grayFrame = new Mat();
    // convert the frame in gray scale
    Imgproc.cvtColor(frame, grayFrame, Imgproc.COLOR_BGR2GRAY);
    //  equalize the frame histogram to  improve the result
    Imgproc.equalizeHist(grayFrame, grayFrame);
    //  compute minimum face size (20%  of the frame height, in our case)
   int absoluteFaceSize = Math.round(height * 0.2f);
    //  detect faces
   faceCascade.detectMultiScale(grayFrame,  faces, 1.1, 2, 0 | Objdetect.CASCADE_SCALE_IMAGE, new Size(absoluteFaceSize, absoluteFaceSize), new Size());
   //  each rectangle in faces is a  face: draw them!
    Rect[] facesArray = faces.toArray();
   for (int i = 0; i < facesArray.length; i++)
   {
      Imgproc.rectangle(frame, facesArray.tl(), facesArray.br(), new Scalar(0, 255, 0), 3);
   }
}

image Matrix of the type CV_8U containing an image where objects are detected.
objects Vector of rectangles where each rectangle contains the detected object.包含人臉的矩形vector
scaleFactor Parameter specifying how much the image size is reduced at each image scale.看不懂默認1.1
minNeighbors Parameter specifying how many neighbors each candidate rectangle should have to retain it.
flags Parameter with the same meaning for an old cascade as in the function cvHaarDetectObjects. It is not used for a new cascade.//Objdetect.CASCADE_FIND_BIGGEST_OBJECT 找最大的人臉目標,一次只獲得一個人臉

minSize Minimum possible object size. Objects smaller than that are ignored.//臉部區域最小下限
maxSize Maximum possible object size. Objects larger than that are ignored.//臉部區域最大上限

Canny 邊緣檢測

private Mat doCanny(Mat frame)
{
    // init
    Mat grayImage = new Mat();
    Mat detectedEdges = new Mat();
    // convert to grayscale
    Imgproc.cvtColor(frame, grayImage, Imgproc.COLOR_BGR2GRAY);
   // reduce noise with a 3x3 kernel
    Imgproc.blur(grayImage, detectedEdges, new Size(3, 3));       
    // canny detector, with ratio of lower:upper threshold of 3:1
    Imgproc.Canny(detectedEdges, detectedEdges, this.threshold.getValue(), this.threshold.getValue() * 3);         
    // using Canny's output as a mask, display the result
    Mat dest = new Mat();
    frame.copyTo(dest, detectedEdges);
    return dest;
}

Canny 邊緣檢測

腐蝕膨脹相關操作

Mat blurredImage = new Mat();
Mat hsvImage = new Mat();
Mat mask = new Mat();
Mat morphOutput = new Mat();
// remove some noise
Imgproc.blur(frame, blurredImage, new Size(7, 7));//去噪
// convert the frame to HSV
Imgproc.cvtColor(blurredImage, hsvImage, Imgproc.COLOR_BGR2HSV);
/**
* Given a binary image containing one or more closed surfaces, use it as a
* mask to find and highlight the objects contours
* 
* @param maskedImage
* the binary image to be used as a mask
* @param frame
* the original {@link Mat} image to be used for drawing the
*objects contours
*@return the {@link Mat} image with the objects contours framed
*/
private Mat findAndDrawBalls(Mat maskedImage, Mat frame)
{
    // init
    List<MatOfPoint> contours = new ArrayList<>();
    Mat hierarchy = new Mat();
    // find contours
    Imgproc.findContours(maskedImage, contours, hierarchy, Imgproc.RETR_CCOMP, Imgproc.CHAIN_APPROX_SIMPLE);
   // if any contour exist...
   if (hierarchy.size().height > 0 && hierarchy.size().width > 0)
   {
       // for each contour, display it in blue
       for (int idx = 0; idx >= 0; idx = (int) hierarchy.get(0, idx)[0])
        {
            Imgproc.drawContours(frame, contours, idx, new Scalar(250, 0, 0));
        }
    }
    return frame;
}
Mat blurredImage = new Mat();
Mat hsvImage = new Mat();
Mat mask = new Mat();
Mat morphOutput = new Mat();                
// remove some noise
Imgproc.blur(frame, blurredImage, new Size(7, 7));
// convert the frame to HSV
Imgproc.cvtColor(blurredImage, hsvImage, Imgproc.COLOR_BGR2HSV);                   
// get thresholding values from the UI
// remember: H ranges 0-180, S and V range 0-255
Scalar minValues = new Scalar(this.hueStart.getValue(), this.saturationStart.getValue(),
this.valueStart.getValue());
Scalar maxValues = new Scalar(this.hueStop.getValue(), this.saturationStop.getValue(),
this.valueStop.getValue());                                   
// show the current selected HSV range
String valuesToPrint = "Hue range: " + minValues.val[0] + "-" + maxValues.val[0]
+ "\tSaturation range: " + minValues.val[1] + "-" + maxValues.val[1] + "\tValue range: "
+ minValues.val[2] + "-" + maxValues.val[2];
this.onFXThread(this.hsvValuesProp, valuesToPrint);
// threshold HSV image to select tennis balls
Core.inRange(hsvImage, minValues, maxValues, mask);
// show the partial output
this.onFXThread(this.maskImage.imageProperty(), this.mat2Image(mask));
// morphological operators
// dilate with large element, erode with small ones
Mat dilateElement = Imgproc.getStructuringElement(Imgproc.MORPH_RECT, new Size(24, 24));
Mat erodeElement = Imgproc.getStructuringElement(Imgproc.MORPH_RECT, new Size(12, 12));
Imgproc.erode(mask, morphOutput, erodeElement);
Imgproc.erode(mask, morphOutput, erodeElement);//腐蝕          
Imgproc.dilate(mask, morphOutput, dilateElement);
Imgproc.dilate(mask, morphOutput, dilateElement);//膨脹
// show the partial output
this.onFXThread(this.morphImage.imageProperty(), this.mat2Image(morphOutput));
// find the tennis ball(s) contours and show them
frame = this.findAndDrawBalls(morphOutput, frame);

直方圖 opencv c++ VS java 版本對比

C++:  
void calcHist(vector_Mat images, vector_int channels, Mat mask, Mat& hist, vector_int histSize, vector_float ranges, bool accumulate = false)
void calcHist( InputArrayOfArrays images, const vector<int>& channels,InputArray mask, OutputArray hist,const vector<int>& histSize,const                 vector<float>& ranges,bool accumulate=false );
//java:
//void calcHist(List<Mat> images, MatOfInt channels, //Mat mask, Mat hist, MatOfInt histSize, MatOfFloat //ranges, boolean accumulate)
//紅褐色字體是java版本的
Mat src, dst;

// 裝載圖像
Mat src = imread( "文件路徑" );
Mat frame= Imgproc.imread( "文件路徑" );

/// 分割成3個單通道圖像 ( R, G 和 B )
vector<Mat> rgb_planes;
split(src, rgb_planes );
//List<Mat> images = new ArrayList<Mat>();
//Core.split(frame, images);
/// 設定bin數目
int histSize = 255;

/// 設定取值範圍 ( R,G,B) )
float range[] = { 0, 255 } ;
const float* histRange = { range };

//MatOfInt histSize = new MatOfInt(256);
//MatOfFloat histRange = new MatOfFloat(0, 256);
//MatOfInt channels = new MatOfInt(0);

bool uniform = true; bool accumulate = false;

Mat r_hist,g_hist, b_hist;
//Mat hist_b = new Mat();
//Mat hist_g = new Mat();
//Mat hist_r = new Mat();
/// 計算直方圖:
    calcHist(&rgb_planes[0], 1,0,Mat(),r_hist, 1, &histSize, &histRange, uniform,accumulate );
    calcHist(&rgb_planes[1], 1,0,Mat(),g_hist, 1, &histSize, &histRange, uniform, accumulate );
    calcHist(&rgb_planes[2], 1,0,Mat(),b_hist, 1, &histSize, &histRange, uniform, accumulate );
//Imgproc.calcHist(images.subList(0,1),channels,new Mat(),hist_b,histSize,histRange,false);
//Imgproc.calcHist(images.subList(1,2),channels,new Mat(),hist_g,histSize,histRange,false);
//Imgproc.calcHist(images.subList(2,3),channels,new Mat(),hist_r,histSize,histRange,false);
// 創建直方圖畫布
int hist_w = 400;
int hist_h = 400;
int bin_w = cvRound( (double) hist_w/histSize );
//int hist_w = 400; // width of the histogram image
//int hist_h = 400; // height of the histogram image
//int bin_w = (int) Math.round(hist_w / histSize.get(0, 0)[0]);
Mat histImage(hist_w, hist_h, CV_8UC3, Scalar( 0,0,0) );
//Mat histImage = new Mat(hist_h, hist_w, CvType.CV_8UC3, new Scalar(0, 0, 0));
/// 將直方圖歸一化到範圍 [ 0, histImage.rows ]
normalize(r_hist,r_hist, 0, histImage.rows, NORM_MINMAX, -1, Mat() );
normalize(g_hist,g_hist, 0, histImage.rows, NORM_MINMAX, -1, Mat() );
normalize(b_hist,b_hist, 0, histImage.rows, NORM_MINMAX, -1, Mat() );
//Core.normalize(hist_b, hist_b, 0, histImage.rows(), Core.NORM_MINMAX, -1, new Mat());
//Core.normalize(hist_g, hist_g, 0, histImage.rows(), Core.NORM_MINMAX, -1, new Mat());
//Core.normalize(hist_r, hist_r, 0, histImage.rows(), Core.NORM_MINMAX, -1, new Mat());
/// 在直方圖畫布上畫出直方圖
for( int i = 1; i < histSize; i++ )
{
    line(histImage, Point( bin_w*(i-1), hist_h - cvRound(r_hist.at<float>(i-1)) ) ,
    Point( bin_w*(i), hist_h - cvRound(r_hist.at<float>(i)) ),
    Scalar( 0, 0, 255), 2, 8, 0  );
    line(histImage, Point( bin_w*(i-1), hist_h - cvRound(g_hist.at<float>(i-1)) ) ,
    Point( bin_w*(i), hist_h - cvRound(g_hist.at<float>(i)) ),
    Scalar( 0, 255, 0), 2, 8, 0  );
    line( histImage, Point( bin_w*(i-1), hist_h - cvRound(b_hist.at<float>(i-1)) ) ,
    Point( bin_w*(i), hist_h - cvRound(b_hist.at<float>(i)) ),
    Scalar( 255, 0, 0), 2, 8, 0  );
}
// effectively draw the histogram(s)
//for (int i = 1; i < histSize.get(0, 0)[0]; i++)
//{
//// B component or gray image
//  Core.line(histImage, new Point(bin_w * (i - 1),hist_h - Math.round(hist_b.get(i - 1, 0)[0])),new Point(bin_w * (i), hist_h -Math.round(hist_b.get(i, 0)[0])), new Scalar(255, 0, 0), 2, 8, 0);
//// G and R components (if the image is not in gray scale)
//  Core.line(histImage, new Point(bin_w * (i - 1), hist_h - Math.round(hist_g.get(i - 1, 0)[0])),new Point(bin_w * (i), hist_h -Math.round(hist_g.get(i, 0)[0])), new Scalar(0, 255, 0), 2, 8,0);
//  Core.line(histImage, new Point(bin_w * (i -1),hist_h - Math.round(hist_r.get(i - 1, 0)[0])),new Point(bin_w * (i), hist_h -Math.round(hist_r.get(i, 0)[0])), new Scalar(0, 0, 255), 2, 8,0);
}
    Image histImg = mat2Image(histImage);
/// 顯示直方圖
    namedWindow("calcHist Demo", CV_WINDOW_AUTOSIZE );
    imshow("calcHist Demo", histImage );
    waitKey(0);
    return 0;
}
//private Image mat2Image(Mat frame)
//{
//// create a temporary buffer
//  MatOfByte buffer = new MatOfByte();
//// encode the frame in the buffer, according to the //PNG format
//  Imgcodecs.imencode(".png", frame, buffer);
//// build and return an Image created from the image //encoded in the  buffer
//  return new Image(new //ByteArrayInputStream(buffer.toArray()));
//}

GrabCut 函數應用 人臉皮膚抓取

/*
GC_BGD = 0,
GC_FGD = 1,
GC_PR_BGD = 2,
GC_PR_FGD = 3,
GC_INIT_WITH_RECT = 0,
GC_INIT_WITH_MASK = 1,
GC_BGD defines an obvious background pixels.
GC_FGD defines an obvious foreground (object) pixel.
GC_PR_BGD defines a possible background pixel.
GC_PR_FGD defines a possible foreground pixel.
*/
Mat bgdModel=new Mat();//暫時沒用
Mat fgdModel=new Mat();//暫時沒用
Mat grabSkin=new Mat(orgBGRImageSmall.size(),CvType.CV_8U);
float a2=160*160;
float b2=115*115;
byte ellipseMask[]=new byte[smallWidth*smallHeight];
for (int i = 0; i <smallHeight; i++) 
{
    for (int j = 0; j <smallWidth; j++)
    {
        if (((i-170)*(i-170)/a2+(j-120)*(j-120)/b2)<1)
        {
            ellipseMask[i*smallWidth+j]=(byte)3;
        //==3纔是前景圖像也就是皮膚區域
        }
    }
}
grabSkin.put(0,0,ellipseMask);
//橢圓 掩膜 可能會有皮膚的區域Mask

Imgproc.grabCut(orgBGRImageSmall,grabSkin,rectOfSmallFace,bgdModel,fgdModel,3,Imgproc.GC_INIT_WITH_MASK);
Scalar aaScalar=new Scalar(3);
Mat grabSkinTmp0=new Mat();
Core.compare(maskSkin,aaScalar,grabSkinTmp0,Core.CMP_EQ);

原圖
GrabSkin

Template Match
import org.opencv.core.Core;
import org.opencv.core.Core.MinMaxLocResult;
import org.opencv.core.Mat;
import org.opencv.core.Point;
import org.opencv.core.Scalar;
import org.opencv.imgcodecs.Imgcodecs;
import org.opencv.imgproc.Imgproc;
public class TemplateMatching {
    public static void main(String[] args) {
        System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
        Mat source=null;
        Mat template=null;
        String filePath="C:\\Users\\mesutpiskin\\Desktop\\Object Detection\\Template Matching\\Sample Image\\";
        //Load image file
        source=Imgcodecs.imread(filePath+"kapadokya.jpg");
        template=Imgcodecs.imread(filePath+"balon.jpg");
        Mat outputImage=new Mat();    
        int machMethod=Imgproc.TM_CCOEFF;
        //Template matching method
        Imgproc.matchTemplate(source, template, outputImage, machMethod);
        MinMaxLocResult mmr = Core.minMaxLoc(outputImage);
        Point matchLoc=mmr.maxLoc;
        //Draw rectangle on result image
        Imgproc.rectangle(source, matchLoc, new Point(matchLoc.x + template.cols(),
                matchLoc.y + template.rows()), new Scalar(255, 255, 255));
        Imgcodecs.imwrite(filePath+"sonuc.jpg", source);
        System.out.println("Complated.");
    }
}

模板匹配

神經網絡java+opencv2.X
訓練


CvANN_MLP ann=new CvANN_MLP();
Mat layerSize=new Mat(4,1,CvType.CV_32SC1);
int[] layerSizeAry={4, 10,10, 3};
layerSize.put(0,0,layerSizeAry[0]);
layerSize.put(1,0,layerSizeAry[1]);
                layerSize.put(2,0,layerSizeAry[2]);
layerSize.put(3,0,layerSizeAry[3]);
ann.create(layerSize);
Mat sampleWeights=new Mat();
int r=ann.train(TrainingDataMat,TrainingLabelsMat,sampleWeights);
ann.save("ann.xml");
測試/預測
Mat results=new Mat(); 
CvANN_MLP ann=new CvANN_MLP();
ann.load("ann.xml");
Mat sampleMat=new Mat(1,featuresArray.length,CvType.CV_32F);
sampleMat.put(0,0,featuresArray);
ann.predict(sampleMat, results);    //MLP預測
MinMaxLocResult minMaxLocResult0=Core.minMaxLoc(results);
System.out.println("results="+results.dump());
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章