OpenCV:检测颜色并在颜色上画线 [英] OpenCV: Detect color and draw line on color

查看:398
本文介绍了OpenCV:检测颜色并在颜色上画线的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我的应用程序将要计算电池的跳动高度,我打算使用蓝色条来定义基数",在该基数中,我将使用该基数来计算电池离电池的像素数.

My application is going to calculate the bounce height of the battery, I intend to use the blue strip to define the "base" in which i use to calculate the number of pixels away it is from the battery.

我如何检测该蓝色并在蓝色纸条的底部画一条线,以便将画出的线用于像素距离计算?

How do i detect that blue color and draw a line at the base of the blue strip of paper such that the line drawn could be used for pixel distance calculation?

我知道opencv有一个斑点检测应用程序,可以围绕选定的颜色绘制轮廓,但是我需要的是自动检测颜色和颜色的应用程序.给我一个坐标,这样我就可以申请

I'm aware that opencv has a blob detection application that draws contours around a color that was selected, but what I need is the application to automatically detect the color & give me it's co-ordinate such that i can apply

canvas.drawLine(0, 0, 20, 20, p);

画线

注意:检测&线条画是在从视频中提取的位图图像上完成的.

Note: the detection & line drawing is done on an bitmap image extracted from a video.

当我测试出来时,它没有检测到蓝色.我什至在具有蓝色和绿色彩色纸的图片上进行了测试,但是输出dint检测到蓝色...

When i tested it out, it doesnt detect the blue color. i even tested it out on pictures that has blue and green colored paper, but the output dint detect blue...

这是我的照片: 这是我当前的代码:

Here's my pictures: Here's my current code:

Mat hsvMat = new Mat();
            //Mat black_hue_range = new Mat();
            //Core.inRange(hsvMat, new Scalar(0, 0, 0), new Scalar(180, 255, 30, 0), black_hue_range);
            Mat blue_hue = new Mat();
            Scalar lower_blue = new Scalar(110,50,50);
            Scalar upper_blue = new Scalar(130,255,255);

            //Convert BGR to HSV
            Imgproc.cvtColor(srcMat, hsvMat, Imgproc.COLOR_BGR2HSV);

            //Threshold the HSV image to get only blue colors
            Core.inRange(hsvMat, lower_blue, upper_blue, blue_hue); // hue == a colour or shade
            Mat tempMat22 = new Mat();
            Core.bitwise_and(hsvMat,hsvMat,tempMat22,blue_hue);
            Utils.matToBitmap(tempMat22, b);

            //Bitmap mutableBitmap = b.copy(Bitmap.Config.ARGB_8888, true);
            imgR.setImageBitmap(b);

以下代码返回了我认为是H = data[0], S data[1], V = data[2]的三个值 现在我有了HSV值,如何获得上限和下限?亚历山大·雷诺兹(Alexander Reynolds)给出的答案

The following code returned three values which i assumed was H = data[0], S data[1], V = data[2] Now that i have the HSV value how do i get the upper and lower limit? The answer given by Alexander Reynolds here seems to be for RGB and not HSV. Note: The color pixel im reading now is Green, not blue anymore.

E/数据:H:90.0 S:113.0 V:144.0

E/data: H:90.0 S:113.0 V:144.0

if (getIntent().hasExtra("byteArray")) {

            bitmap = BitmapFactory.decodeByteArray(getIntent().getByteArrayExtra("byteArray"), 0, getIntent().getByteArrayExtra("byteArray").length);

            int width= bitmap.getWidth();
            int height=bitmap.getHeight();

            int centerX=width/2;
            int centerY=height/2;
            srcMat = new Mat();
            Utils.bitmapToMat(bitmap, srcMat);
            Imgproc.cvtColor(srcMat, srcMat, Imgproc.COLOR_BGR2HSV);
            srcMat.convertTo(srcMat, CvType.CV_64FC3); //http://answers.opencv.org/question/14961/using-get-and-put-to-access-pixel-values-in-java/
            double[] data = srcMat.get(centerX, centerY);
            Log.e("data", String.valueOf("H:"+data[0]+" S:"+data[1]+" V:"+data[2]));
            Log.e("dlength", String.valueOf(data.length));
            Mat matHSV = new Mat(0,0,CvType.CV_64FC3);

此外,通过添加以下三行代码,我将收到一条错误消息,指出bitmap == null,因此我无法真正确定像素读取是否有效.

Also by adding the following three lines of code, i'll receive an error saying bitmap == null, so im not really sure if the pixel reading worked or not.

matHSV.put(0,0,data);
Utils.matToBitmap(matHSV, bb);
imgDisplay.setImageBitmap(bb);

尝试使用Rect指定ROI时出现错误:

I'm getting an error when trying to specify the roi using Rect:

起因:CvException [org.opencv.core.CvException:cv :: Exception:/build/master_pack-android/opencv/modules/core/src/matrix.cpp:483:错误:(-215)0< ; = _rowRange.start&& _rowRange.start< = _rowRange.end&& _rowRange.end< = m.rows in function cv :: Mat :: Mat(const cv :: Mat& ;, const cv :: Range& ;, const cv :: Range&)

Caused by: CvException [org.opencv.core.CvException: cv::Exception: /build/master_pack-android/opencv/modules/core/src/matrix.cpp:483: error: (-215) 0 <= _rowRange.start && _rowRange.start <= _rowRange.end && _rowRange.end <= m.rows in function cv::Mat::Mat(const cv::Mat&, const cv::Range&, const cv::Range&)

bitmap = globals.getBmp();
        Mat srcMat = new Mat();
        Utils.bitmapToMat(bitmap, srcMat);

        Mat hsvMat = new Mat();
        Imgproc.cvtColor(srcMat,hsvMat,Imgproc.COLOR_BGR2HSV);

    Mat roiMat;
            Rect rectangle = new Rect(177,1571,822,1680);// 177,1571(top right corner),   820,1680 (btm right) 820, 1565(topright)
            roiMat = new Mat(hsvMat,rectangle);
            Utils.matToBitmap(roiMat, temp);

            ImageView imageView = (ImageView) findViewById(R.id.imageView);
            imageView.setImageBitmap(temp);

我也尝试使用Range:

 Range rowRange = new Range(177, 822);
        Range colRange = new Range(1571, 1680);
        roiMat = new Mat(hsvMat, rowRange, colRange); // public Mat(Mat m, Range rowRange, Range colRange)

EDIT2.5:

更改:

roiMat = new Mat(hsvMat, rowRange, colRange);

收件人:

roiMat = new Mat(hsvMat, colRange, rowRange); 

似乎已解决了该问题,但现在说的是我的bmp

seemed to have fixed the issue, but now it's saying my bmp

java.lang.IllegalArgumentException:bmp == null

java.lang.IllegalArgumentException: bmp == null

最终设法转换了亚历山大·雷诺兹(Alexander Reynolds)回答的python代码, 但由于出现错误,我似乎无法查看结果:

EDIT 3: Finally managed to convert the python code answered by Alexander Reynolds, But i cant seem to view the result as I'm getting an error:

java.lang.IllegalArgumentException:bmp == null

java.lang.IllegalArgumentException: bmp == null

at

Utils.matToBitmap(idk,temp);

bitmap = cn.getBmp();
    Mat srcMat = new Mat();
    Utils.bitmapToMat(bitmap, srcMat);

    Mat hsvMat = new Mat();
    Imgproc.cvtColor(srcMat,hsvMat,Imgproc.COLOR_BGR2HSV);

    Mat roiMat;
    Rect rectangle = new Rect(177,1571,822,1680);// 177,1571(top right corner),   820,1680 (btm right) 820, 1565(topright)
    Range rowRange = new Range(177, 822);
    Range colRange = new Range(1571, 1680);
    roiMat = new Mat(hsvMat, colRange, rowRange); // public Mat(Mat m, Range rowRange, Range colRange)

    MatOfDouble mu = new MatOfDouble();
    MatOfDouble sig = new MatOfDouble();

    Core.meanStdDev(roiMat,mu,sig);


    double m = mu.get(0,0)[0];
    double d = sig.get(0,0)[0];
    int a = 9;
    Log.e("m , d", "m "+String.valueOf(m)+" d"+String.valueOf(d));
    Mat blue_mask = new Mat();
    Core.inRange(hsvMat, new Scalar(m-a*d), new Scalar(m+a*d), blue_mask); // javadoc: inRange(src, lowerb, upperb, dst)
    Mat idk = new Mat();
    Core.bitwise_and(hsvMat,hsvMat,idk,blue_mask);
    Utils.matToBitmap(idk,temp);
    Bitmap mutableBitmap = temp.copy(Bitmap.Config.ARGB_8888, true);

推荐答案

您可以使用内置的OpenCV方法

You can perform color filtering with the built-in OpenCV method inRange() which will allow you to create a mask containing white wherever any pixel values fall between a defined lower bound and upper bound, and black otherwise. From there you can simply find the location of the white pixels in the mask.

有关示例,请参见本教程.

此外,我以前的回答此处给出了一些建议,以找到良好的上下限-特别是,找到在您知道的图像中的某个区域(如链接的区域)上具有所需的颜色,并找到这些值的平均值和标准偏差(在任何色彩空间中,但我可能建议从HSV或HLS开始).然后,您可以轻松地将下限设置为mean-a*stddev,将上限设置为mean+b*stddev,其中ab是可以尝试使用的一些值,以查看哪种方法最适合选择蓝色(仅蓝色).您可以以a=b开头,并为它们使用整数值(1、2、3,...),然后从那里进行磨练.

Also, my previous answer here gives some suggestions for finding good lower and upper bounds---in particular, find an area in an image you know (like the one linked) with the color you want, and find the mean and standard deviation of those values (in any colorspace, but I would probably suggest starting with HSV or HLS). Then you can easily set the lower bound to mean-a*stddev and upper bound to mean+b*stddev where a and b are some values you can experiment with to see what works best at selecting the blue (and only the blue). You can start with a=b and use integer values for them (1, 2, 3, ...) and hone in from there.

一旦有了遮罩,很可能会在其中蒙上一些洞或在图像的其他位置出现多余的白色像素.您可以使用轮廓检测​​,高线检测或斑点检测来获取正确的矩形.在这种情况下,我建议使用 boundingRect 周围,这将直接为您提供像素位置.

Once you have the mask, it's likely you'll have a few holes in it or extraneous white pixels elsewhere in the image. You can use contour detection, Hough line detection, or blob detection to get the correct rectangle. In this case, I would suggest using contour detection on the mask with findContours(), find the largest contour, find the boundingRect around it, and that will give you the pixel locations directly.

您使用的是C ++,但是Python提供示例的速度更快,因此您必须进行翻译.我将使用第一张图片的调整大小版本:

You're working in C++ but Python is faster for giving examples, so you'll have to translate. I'll use a resized version of your first image:

import numpy as np
import cv2

img = cv2.imread('image.jpg')
img = cv2.resize(img, None, fx=0.1, fy=0.1)
hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
roi = hsv[430:450, 20:170]

在这里,我只是在调整图像的大小(主要是为了便于显示),转换色彩空间,并定义仅包含蓝色像素的感兴趣区域(ROI).在BGR中,ROI如下所示:

Here I'm just resizing the image (mostly so I can display it easily), converting the colorspace, and defining a region of interest (ROI) that only includes blue pixels. In BGR, the ROI looks like this:

此ROI仅包含蓝色像素,因此我可以找到平均值蓝色值和蓝色值的标准偏差作为inRange()的值

This ROI contains only blue pixels, so I can find the mean blue value, and the standard deviation of the blue values to use as the values for inRange().

mu, sig = cv2.meanStdDev(roi)
a = 9

blue_mask = cv2.inRange(hsv, mu-a*sig, mu+a*sig)

因此,我们只有蓝色值的蒙版:

Thus we have a mask of just the blue values:

从这里您可以进行常规轮廓检测并找到其周围的边界框:

From here you can do your normal contour detection and find the bounding box around it:

_, contours, _ = cv2.findContours(blue_mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
x, y, w, h = cv2.boundingRect(contours[0])
cv2.rectangle(img, (x,y), (x+w,y+h), (0,255,0), 2)

现在我们在原始图像中的石蕊试纸周围有了一个包围矩形(我们有左上角的位置以及宽度和高度):

And now we have a bounding rectangle (we have the location of the upper left corner, and the width and height) around the litmus paper in the original image:

这篇关于OpenCV:检测颜色并在颜色上画线的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆