我是OpenCV4Android的新手。这是我编写的一些代码,用于检测图像中的蓝色斑点。在下面的图像中,图像1在我的笔记本电脑中。我运行应用程序,OpenCV摄像头捕获的帧是图像2.您可以查看代码以查看其余图像是什么。 (正如您在代码中看到的,所有图像都保存在SD卡中。)
我有以下问题:。
为什么在相机拍摄的rgba帧中,浅蓝色斑点的颜色变成浅黄色(如图2所示)。
我在最大的蓝色斑点周围创建了一个boundingRect
,然后通过ROI
创建了rgbaFrame.submat(detectedBlobRoi)
。但是你可以在最后一张图片中看到它看起来像几个灰色像素。 我期待蓝色球体与图像的其余部分分开。
我错过了什么或做错了什么?
CODE:
private void detectColoredBlob () {
Highgui.imwrite("/mnt/sdcard/DCIM/rgbaFrame.jpg", rgbaFrame);//check
Mat hsvImage = new Mat();
Imgproc.cvtColor(rgbaFrame, hsvImage, Imgproc.COLOR_RGB2HSV_FULL);
Highgui.imwrite("/mnt/sdcard/DCIM/hsvImage.jpg", hsvImage);//check
Mat maskedImage = new Mat();
Scalar lowerThreshold = new Scalar(170, 0, 0);
Scalar upperThreshold = new Scalar(270, 255, 255);
Core.inRange(hsvImage, lowerThreshold, upperThreshold, maskedImage);
Highgui.imwrite("/mnt/sdcard/DCIM/maskedImage.jpg", maskedImage);//check
Mat dilatedMat= new Mat();
Imgproc.dilate(maskedImage, dilatedMat, new Mat() );
Highgui.imwrite("/mnt/sdcard/DCIM/dilatedMat.jpg", dilatedMat);//check
List<MatOfPoint> contours = new ArrayList<MatOfPoint>();
Imgproc.findContours(dilatedMat, contours, new Mat(), Imgproc.RETR_LIST, Imgproc.CHAIN_APPROX_SIMPLE);
//Use only the largest contour. Other contours (any other possible blobs of this color range) will be ignored.
MatOfPoint largestContour = contours.get(0);
double largestContourArea = Imgproc.contourArea(largestContour);
for ( int i=1; i<contours.size(); ++i) {//NB Notice the prefix increment.
MatOfPoint currentContour = contours.get(0);
double currentContourArea = Imgproc.contourArea(currentContour);
if (currentContourArea > largestContourArea) {
largestContourArea = currentContourArea;
largestContour = currentContour;
}
}
Rect detectedBlobRoi = Imgproc.boundingRect(largestContour);
Mat detectedBlobRgba = rgbaFrame.submat(detectedBlobRoi);
Highgui.imwrite("/mnt/sdcard/DCIM/detectedBlobRgba.jpg", detectedBlobRgba);//check
}
编辑:
我刚刚使用Core.inRange(hsvImage, new Scalar(0,50,40), new Scalar(10,255,255), maskedImage);//3, 217, 225 --- 6, 85.09, 88.24 ...... 3 219 255
,我通过给它一个红色的自定义HSV值,即为OpenCV红色Scalar(3, 217, 255)
(属于范围)捕获了网站colorizer.org的screeshot在给定的inRange
函数中设置,我将通道值缩放到colorizer.org的比例,即H = 0-360,S = 0-100,V = 0-100,通过将H值乘以2 ,并将S和V值除以255并乘以100.这给了我6, 85.09, 88.24
我在网站上设置,并截取屏幕截图(下图中的第一个)。
重要:
当我触摸rgbaFrame(即在onTouch
方法中调用)时,实际上在我的测试应用程序中调用了给定的方法。我还使用以下代码打印到TextView
我所触摸的彩色blob的Hue
,Saturation
和Value
值。 当我运行此应用程序时,我触摸了红色斑点,并获得了以下值:Hue:3, Saturation:219, Value:255
。
public boolean onTouch(View v,MotionEvent motionEvent){ detectColoredBlob(); int cols = rgbaFrame.cols(); int rows = rgbaFrame.rows();
int xOffset = (openCvCameraBridge.getWidth() - cols) / 2;
int yOffset = (openCvCameraBridge.getHeight() - rows) / 2;
int x = (int) motionEvent.getX() - xOffset;
int y = (int) motionEvent.getY() - yOffset;
Log.i(TAG, "Touch image coordinates: (" + x + ", " + y + ")");//check
if ((x < 0) || (y < 0) || (x > cols) || (y > rows)) { return false; }
Rect touchedRect = new Rect();
touchedRect.x = (x > 4) ? x - 4 : 0;
touchedRect.y = (y > 4) ? y - 4 : 0;
touchedRect.width = (x + 4 < cols) ? x + 4 - touchedRect.x : cols - touchedRect.x;
touchedRect.height = (y + 4 < rows) ? y + 4 - touchedRect.y : rows - touchedRect.y;
Mat touchedRegionRgba = rgbaFrame.submat(touchedRect);
Mat touchedRegionHsv = new Mat();
Imgproc.cvtColor(touchedRegionRgba, touchedRegionHsv, Imgproc.COLOR_RGB2HSV_FULL);
double[] channelsDoubleArray = touchedRegionHsv.get(0, 0);//**********
float[] channelsFloatArrayScaled = new float[3];
for (int i = 0; i < channelsDoubleArray.length; i++) {
if (i == 0) {
channelsFloatArrayScaled[i] = ((float) channelsDoubleArray[i]) * 2;// TODO Wrap an ArrayIndexOutOfBoundsException wrapper
} else if (i == 1 || i == 2) {
channelsFloatArrayScaled[i] = ((float) channelsDoubleArray[i]) / 255;// TODO Wrap an ArrayIndexOutOfBoundsException wrapper
}
}
int androidColor = Color.HSVToColor(channelsFloatArrayScaled);
view.setBackgroundColor(androidColor);
textView.setText("Hue : " + channelsDoubleArray[0] + "\nSaturation : " + channelsDoubleArray[1] + "\nValue : "
+ channelsDoubleArray[2]);
touchedRegionHsv.release();
return false; // don't need subsequent touch events
}
答案 0 :(得分:4)
你使用的范围可能是蓝色错误,在OpenCV中,色调范围是0-180,你已经给出了170-270。找到蓝色的正确色调值,并在inRange中使用。
您可以在此处参考答案来选择正确的hsv值。
下面是分割红色的代码,用你的代码检查,并确保它分割红色对象。
$customClaims = [
'sub' => $user->id,
'iat' => time(),
'exp' => time() + (2 * 7 * 24 * 60 * 60)
];
$payload = app('tymon.jwt.payload.factory')->make($customClaims);
答案 1 :(得分:3)
将图像转换为HSV色彩空间并使用HSV色彩空间时有多个陷阱。
OpenCV使用压缩的色调范围,因为原始色调范围从0到360,这意味着值不能适合1个字节(值0到255),而饱和度和值通道完全被1个字节覆盖。因此,OpenCV使用色调值除以2.因此色调通道将被0到180之间的矩阵条目覆盖。对此,在OpenCV中,您的色调范围170到270应除以2 =范围65到135。
色调告诉您色调,但饱和度和值对于降低噪点仍然很重要,因此将阈值设置为某个最小饱和度和值
非常重要:OpenCV使用BGR内存排序进行渲染和图像保存。这意味着如果您的图像具有RGB(a)排序并且您保存它而没有颜色转换,则您交换R和B通道,因此假设红色将变为蓝色等。不幸的是,通常您无法从图像数据本身读取,它是RGB或BGR有序的,所以你应该尝试从图像源找到它。 OpenCV允许几个标志从RGB(A)转换为HSV和/或从BGR(A)转换为HSV,和/或从RGB转换为BGR等,这样就没问题,只要你知道你的图像是哪种内存格式使用。但是,显示和保存始终采用BGR排序,因此如果要显示或保存图像,请将其转换为BGR!但是,无论您是使用BGR2HSV转换BGR图像还是使用RGB2HSV转换RGB图像,HSV值都是相同的。但是如果你使用RGB2HSV或带有BGR2HSV的RGB图像转换BGR图像,它将会有错误的值...我不是100%肯定openCV的Java / Python / Android API,但你的图像看起来真的像B和R通道被交换或误解(但是因为你使用RGBA2HSV转换对hsv颜色没有问题)。
关于你的轮廓提取,你的代码中有一个很小的(复制粘贴?)错误,每个人偶尔会观察到这个错误:
MatOfPoint largestContour = contours.get(0);
double largestContourArea = Imgproc.contourArea(largestContour);
for ( int i=1; i<contours.size(); ++i) {//NB Notice the prefix increment.
// HERE you had MatOfPoint currentContour = contours.get(0); so you tested the first contour in each iteration
MatOfPoint currentContour = contours.get(i);
double currentContourArea = Imgproc.contourArea(currentContour);
if (currentContourArea > largestContourArea) {
largestContourArea = currentContourArea;
largestContour = currentContour;
}
}
所以可能只需将此更改为在循环中使用i
而不是0
MatOfPoint currentContour = contours.get(i);