文章目录
-
库加载
-
图像读取
-
色域转换
-
直方图均衡化
-
输出二值图像
-
处理噪点
-
轮廓识别
-
结果处理
-
轮廓绘制
Java使用OpenCV进行颜色识别
流程
-
库加载
-
图像读取
-
色域转换
-
直方图均衡化(选用)
-
输出二值图像
-
噪点处理
-
轮廓识别
-
结果解析
详细步骤
库加载
System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
图像读取
将图片读入到Mat中
Mat srcImgMat = Imgcodecs.imread(filename);
色域转换
读入的如果是RGB格式的文件,首先将图片转换到HSV色域中。具体什么事HSV自行百度。(选做。如果色彩情况复杂或者动态变化范围较大,建议)
Imgproc.cvtColor(srcImgMat, desImaMat, Imgproc.COLOR_RGB2HSV);
直方图均衡化
直方图均衡化可以增加颜色之间的对比度,更容易识别轮廓。由于目标颜色比较简单,所以此处略过。
输出二值图像
这里给出想要识别的颜色的阈值范围,使用的是HSV色域。
如果你在一开始没有转换到HSV色域,则继续使用BGR来确定阈值的范围。
opencv HSV色域范围是H:0-179, S:0-255, V:0-255
建议此处根据不同场景多做调试。
写一个简单的有滑块的gui调试窗口并调用inRange,然后实时显示更方便调试。
//以蓝色为例
Scalar lowerbScalar = new Scalar(100,50,50); //hsv色域的蓝色最低阈值
Scalar highbScalar = new Scalar(130, 255, 255); //hsv色域蓝色最高阈值
//获得二值图像。结果存到desImgMag
Core.inRange(desImgMat, lowerbScalar, highbScalar, desImgMat);
处理噪点
上一步的结果可以直接通过显示出来;
HighGui.imshow(desImgMat);
HighGui.waitkey(0);
如果现实的二值图像噪点比较多,需要清除噪点。
//open processing 去除噪点,小于5x5的都将忽略
Mat kernel = Imgproc.getStructuringElement(Imgproc.MORPH_RECT, new Size(5,5));
//close processing ,连通区域
Imgproc.morphologyEx(desImgMat, desImgMat, Imgproc.MORPH_CLOSE, kernel);
处理完后,可以再现实图片查看效果。
轮廓识别
List<MatOfPoint> pointsVector = new Vector<MatOfPoint>();
Mat hierarchy = new Mat();
Imgproc.findContours(desImgMat, pointsVector, hierarchy, Imgproc.RETR_CCOMP,Imgproc.CHAIN_APPROX_SIMPLE);
这个函数返回值是一个pointsVector。这个Vector里每个元素都是所探测到的一个目标。第一个参数是要识别的图片,第二个是结果,第三个是一些更复杂的结果。第四个第五个如下:
-
Imgproc.RETR_CCOMP 提取所有轮廓,还有其他的参数,比如RETR_EXTERNAL是提取外层轮廓。
-
Imgproc.CHAIN_APPROX_SIMPLE 压缩水平和垂直方向,只保存对角线方向的元素。例如矩形轮廓只需要4个点来保存信息。
其他的参数自行去官网的文档查阅即可。
结果处理
//result processing
//!!!如果有多个目标,需要表里整个pointsVector
MatOfPoint cntMatOfPoint = pointsVector.get(0);
Rect rect = Imgproc.boundingRect(cntMatOfPoint);
int x = rect.x;
int y = rect.y;
int w = rect.width;
int h = rect.height;
由于我测试的只有一个待检测物体,所以只取了第0个。
这样就得到了矩形轮廓。
轮廓绘制
将目标用红色矩形圈起来。如果想得到坐标,就直接通过x,y,w,h计算就行。
//Draw the rectangle outline
Imgproc.rectangle(srcImgMat, new Point(x,y), new Point(x+w, y+h) , new Scalar(0,0,255));;
String window_name = "show";
HighGui.imshow(window_name,desImgMat);
HighGui.imshow(window_name, srcImgMat);
HighGui.waitKey(1);