文章目录

  • Java使用OpenCV进行颜色识别
  • 流程
  • 详细步骤
  • 库加载
  • 图像读取
  • 色域转换
  • 直方图均衡化
  • 输出二值图像
  • 处理噪点
  • 轮廓识别
  • 结果处理
  • 轮廓绘制


Java使用OpenCV进行颜色识别

流程

  1. 库加载
  2. 图像读取
  3. 色域转换
  4. 直方图均衡化(选用)
  5. 输出二值图像
  6. 噪点处理
  7. 轮廓识别
  8. 结果解析

详细步骤

库加载

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);