工作需要,用到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 images = new ArrayList();
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"%d ",*p++);
}
背景去除 简单案列,只适合背景单一的图像
private Mat doBackgroundRemoval(Mat frame)
{
// init
Mat hsvImg = new Mat();
List 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;
}
腐蚀膨胀相关操作
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 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 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 rgb_planes;
split(src, rgb_planes );
//List images = new ArrayList();
//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 for (int j = 0; 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);
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());