今天就来记录一下在Java中使用Opencv得配置吧,至于OpenCV的使用很简单,现成API的调用,查查文档就好了,但是关于OpenCV 这些API背后的原理就需要去学习一下数字图像处理的知识了。推荐冈萨雷斯的《数字图像处理》,这本书真的很棒棒呢
一、OpenCV官网下载opencv到本地,比如我下载到本地目录:F:\opencv3
二、新建一个Java项目,然后在其Project Structure中加入我们下载的OpenCV .jar文件。
三、从本地文件中加载动态库
static {
System.load("F:\\opencv3\\opencv\\build\\java\\x64\\opencv_java455.dll");
}
四、使用
最后就是使用啦,我用它计算一个图形的重心,思路就是,带有目标物的图像通过背差法减掉背景图,然后通过腐蚀膨胀开运算去除小的噪声,然后Canny边缘检测之后转为二值图,最后加权计算重心位置。有个弊端就是开运算改变了像素点的值,导致重心些微偏移。所以还是采用滤波做噪声消除比较合适。
import org.opencv.core.*;
import org.opencv.highgui.HighGui;
import org.opencv.imgcodecs.Imgcodecs;
import org.opencv.imgproc.Imgproc;
import java.util.ArrayList;
import java.util.List;
public class test {
static {
System.load("F:\\opencv3\\opencv\\build\\java\\x64\\opencv_java455.dll");
}
public static void main(String[] args) {
String aimPicture1 = "C:\\Users\\Administrator\\Desktop\\test\\01.jpg";
String backPicture = "C:\\Users\\Administrator\\Desktop\\test\\background.jpg";
String destPicture = "C:\\Users\\Administrator\\Desktop\\test\\subtract.jpg";
Mat aim1 = Imgcodecs.imread(aimPicture1);
Point p1=dotest(aim1, backPicture, destPicture);
System.out.println("x:"+p1.x);
System.out.println("y:"+p1.y);
}
public static Point dotest(Mat aim, String backgroundPicture, String destPath) {
Mat background = Imgcodecs.imread(backgroundPicture);
Mat dest = new Mat(aim.size(), aim.type());
//去除背景
Core.subtract(aim, background, dest);
Imgcodecs.imwrite(destPath, dest);
//腐蚀再膨胀
Mat openMat = open(dest);
//拉普拉斯锐化再检测
// Mat laplacianMat = new Mat(openMat.size(),CvType.CV_64F);
// Imgproc.Laplacian(openMat,laplacianMat,3);
// Imgcodecs.imwrite("C:\\Users\\Administrator\\Desktop\\test\\laplacian.jpg",laplacianMat);
// 边缘检测
Mat edgeMat = new Mat(openMat.size(), CvType.CV_64F);
List matList = new ArrayList<>();
Core.split(openMat, matList);
Imgcodecs.imwrite("C:\\Users\\Administrator\\Desktop\\test\\gray0.jpg", matList.get(0));
Imgcodecs.imwrite("C:\\Users\\Administrator\\Desktop\\test\\gray1.jpg", matList.get(1));
Imgcodecs.imwrite("C:\\Users\\Administrator\\Desktop\\test\\gray2.jpg", matList.get(2));
Imgproc.Canny(matList.get(2), edgeMat, 15, 40);
Imgcodecs.imwrite("C:\\Users\\Administrator\\Desktop\\test\\canny.jpg", edgeMat);
//水平线检测,垂直线检测
float[] hori = {-1, -1, -1, 2, 2, 2, -1, -1, -1};
Mat horiMat = new Mat(3, 3, CvType.CV_32F);
horiMat.put(0, 0, hori);
Mat hLineMat = new Mat(openMat.size(), openMat.type());
Imgproc.filter2D(edgeMat, hLineMat, 3, horiMat);
Imgcodecs.imwrite("C:\\Users\\Administrator\\Desktop\\test\\hLineMat.jpg", hLineMat);
float[] veri = {-1, 2, -1, -1, 2, -1, -1, 2, -1};
Mat veriMat = new Mat(3, 3, CvType.CV_32F);
veriMat.put(0, 0, veri);
Mat vLineMat = new Mat(openMat.size(), openMat.type());
Imgproc.filter2D(edgeMat, vLineMat, 3, veriMat);
Imgcodecs.imwrite("C:\\Users\\Administrator\\Desktop\\test\\vLineMat.jpg", vLineMat);
//范围裁剪
int rows = edgeMat.rows();
int cols = edgeMat.cols();
int rows_10 = (int) (rows * 0.2);
int cols_10 = (int) (cols * 0.2);
Mat dstClipRange = edgeMat.rowRange((int) (rows * 0.2), rows - (int) (rows * 0.2))
.colRange((int) (cols * 0.2), cols - (int) (cols * 0.2));
edgeMat.release();
//计算xline sumWeight
int sumWeightx = 0;
int sumX = 0;
for (int i = 0; i < dstClipRange.cols(); i++) {
int sum = 0;
for (int j = 0; j < dstClipRange.rows(); j++) {
sum += dstClipRange.get(j, i)[0];
}
sumWeightx += (i + 1) * sum;
sumX += sum;
}
int sumWeighty = 0;
int sumY = 0;
for (int i = 0; i < dstClipRange.rows(); i++) {
int sum = 0;
for (int j = 0; j < dstClipRange.cols(); j++) {
sum += dstClipRange.get(i, j)[0];
}
sumWeighty += (i + 1) * sum;
sumY += sum;
}
double centerX = sumWeightx / sumX;
double centerY = sumWeighty / sumY;
centerX = centerX + cols_10;
centerY = centerY + rows_10;
Point p = new Point();
p.x =centerX;
p.y=centerY;
System.out.println("x:" + centerX + "y:" + centerY);
return p;
}
public static double getSumY(Mat singleChannelMat, Mat result) {
Core.reduce(singleChannelMat, result, 1, Core.REDUCE_SUM);
Core.MinMaxLocResult max = Core.minMaxLoc(result);
return max.maxVal;
}
public static double getSumX(Mat singleChannelMat, Mat result) {
Core.reduce(singleChannelMat, result, 0, Core.REDUCE_SUM);
Core.MinMaxLocResult max = Core.minMaxLoc(result);
return max.maxVal;
}
public static double getSingleValue(Mat singleChannelMat) {
return getSingleValueFloat(singleChannelMat);
}
public static double getSingleValueFloat(Mat singleChannelMat) {
double sum = 0;
float[] temp = new float[singleChannelMat.rows() * singleChannelMat.cols() * singleChannelMat.channels()];
singleChannelMat.get(0, 0, temp);
for (double v : temp) {
sum += v;
}
return sum;
}
public static Mat open(Mat srcImage) {
Mat element = Imgproc.getStructuringElement(Imgproc.MORPH_RECT, (new Size(10, 10)));
Mat destImage = new Mat(srcImage.size(), CvType.CV_64F);
Imgproc.erode(srcImage, destImage, element); //腐蚀
Imgproc.dilate(destImage, destImage, element); //膨胀
Imgcodecs.imwrite("C:\\Users\\Administrator\\Desktop\\test\\open.jpg", destImage);
return destImage;
}
public static Mat open2(Mat srcImage) {
Mat element = Imgproc.getStructuringElement(Imgproc.MORPH_RECT, (new Size(5, 5)));
Mat destImage = new Mat(srcImage.size(), CvType.CV_64F);
Imgproc.erode(srcImage, destImage, element); //腐蚀
Imgproc.dilate(destImage, destImage, element); //膨胀
return destImage;
}
}
效果也还行吧,就整挺好的。API的调用很简单,但是要游刃有余还是需要学习一下数字图像处理的基本知识。