我的应用程序将计算电池的反弹高度,我打算使用蓝色条带来定义" base"我在其中用来计算它离电池的像素数。
如何检测蓝色并在蓝色纸条的底部画一条线,以便绘制的线可用于像素距离计算?
我知道opencv有一个斑点检测应用程序可以围绕选择的颜色绘制轮廓,但我需要的是自动检测颜色和颜色的应用程序。给我它的协调,以便我可以申请
canvas.drawLine(0, 0, 20, 20, p);
画线
注意:检测&线条图是在从视频中提取的位图图像上完成的。
修改 当我测试它时,它没有检测到蓝色。我甚至在有蓝色和绿色纸的照片上进行了测试,但输出dint检测到蓝色......
这是我的照片: Output Input 这是我目前的代码:
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 here给出的答案似乎是RGB而不是HSV。 注意:现在读取的彩色像素为绿色,不再是蓝色。
E /数据: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);
另外,通过添加以下三行代码,我会收到一个错误,说位图== null,所以我不确定像素读数是否有效。
matHSV.put(0,0,data);
Utils.matToBitmap(matHSV, bb);
imgDisplay.setImageBitmap(bb);
EDIT2:
尝试使用Rect
指定roi时出错:
引起:CvException [org.opencv.core.CvException:cv :: Exception:/build/master_pack-android/opencv/modules/core/src/matrix.cpp:483:错误:(-215)0&lt ; = _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
java.lang.IllegalArgumentException:bmp == null
编辑3: 最后设法转换Alexander Reynolds回答的python代码, 但我似乎无法查看结果,因为我收到了错误:
java.lang.IllegalArgumentException:bmp == null
在
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);
答案 0 :(得分:3)
您可以使用内置的OpenCV方法inRange()
执行颜色过滤,这将允许您创建包含白色的蒙版,只要任何像素值落在定义的下限和上限之间,否则为黑色。从那里你可以简单地找到面具中白色像素的位置。
有关示例,请参阅this tutorial。
另外,我之前的回答here提供了一些寻找好的下限和上限的建议 - 特别是,找到你想知道的图像中的一个区域(如链接的那个),并且找到这些值的平均值和标准差(在任何颜色空间中,但我可能建议从HSV或HLS开始)。然后,您可以轻松地将下限设置为mean-a*stddev
,将上限设置为mean+b*stddev
,其中a
和b
是您可以尝试的一些值,以便查看哪些值最适合选择蓝色(只有蓝色)。您可以从a=b
开始,并为它们使用整数值(1,2,3,...)并从那里进行磨练。
一旦你有了面具,它可能会在其中有一些洞或图像中其他地方的外来白色像素。您可以使用轮廓检测,霍夫线检测或斑点检测来获得正确的矩形。在这种情况下,我建议使用findContours()
在蒙版上使用轮廓检测,找到最大的轮廓,找到它周围的boundingRect
,这将直接为您提供像素位置。
您正在使用C ++,但Python提供示例的速度更快,因此您必须翻译。我将使用第一张图片的调整大小版本:
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看起来像这样:
此ROI仅包含蓝色像素,因此我可以找到蓝色值的 mean 蓝色值和蓝色值的标准差,以用作{{1 }}
inRange()
因此我们只有一个蓝色值的掩码:
从这里你可以进行正常的轮廓检测并找到它周围的边界框:
mu, sig = cv2.meanStdDev(roi)
a = 9
blue_mask = cv2.inRange(hsv, mu-a*sig, mu+a*sig)
现在我们在原始图像中的石蕊试纸周围有一个边界矩形(我们有左上角的位置,宽度和高度):