在下面的代碼中,我執行了以下步驟:爲什麼OpenCV4Android的pointPolygonTest()方法爲每個像素返回-1?
- 從sdcard加載圖像。
它轉換爲HSV格式。
使用
inRange
功能可以遮蔽紅色。用於
findContours
找到輪廓。從這些輪廓中找出最大的輪廓。
使用
boundingRect
和submat
函數創建圍繞最大輪廓的ROI。- 轉換此ROI墊到HSV格式。
通過ROI墊迭代,並檢查對於每個像素,如果它位於最大輪廓內。 我使用方法
pointPolygonTest
來找出這個問題,但是它會爲每個像素返回-1
,從Log.i
輸出I have pasted here可以看出。問題是爲什麼?我該如何糾正這一點。private Scalar detectColoredBlob() { rgbaFrame = Highgui.imread("/mnt/sdcard/DCIM/rgbaMat4Mask.bmp"); Mat hsvImage = new Mat(); Imgproc.cvtColor(rgbaFrame, hsvImage, Imgproc.COLOR_BGR2HSV); Highgui.imwrite("/mnt/sdcard/DCIM/hsvImage.bmp", hsvImage);// check Mat maskedImage = new Mat(); Core.inRange(hsvImage, new Scalar(0, 100, 100), new Scalar(10, 255, 255), maskedImage); Highgui.imwrite("/mnt/sdcard/DCIM/maskedImage.bmp", maskedImage);// check List<MatOfPoint> contours = new ArrayList<MatOfPoint>(); Imgproc.findContours(maskedImage, contours, new Mat(), Imgproc.RETR_LIST, Imgproc.CHAIN_APPROX_SIMPLE); // \/ We will 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(i); double currentContourArea = Imgproc.contourArea(currentContour); if (currentContourArea > largestContourArea) { largestContourArea = currentContourArea; largestContour = currentContour; } } MatOfPoint2f largestContour2f = new MatOfPoint2f(largestContour.toArray());// Required on Line 289. See http://stackoverflow.com/questions/11273588/how-to-convert-matofpoint-to-matofpoint2f-in-opencv-java-api Rect detectedBlobRoi = Imgproc.boundingRect(largestContour); Mat detectedBlobRgba = rgbaFrame.submat(detectedBlobRoi); Highgui.imwrite("/mnt/sdcard/DCIM/detectedBlobRgba.bmp", detectedBlobRgba);// check Mat detectedBlobHsv = new Mat(); Imgproc.cvtColor(detectedBlobRgba, detectedBlobHsv, Imgproc.COLOR_BGR2HSV); Highgui.imwrite("/mnt/sdcard/DCIM/roiHsv.bmp", detectedBlobHsv);// check for (int firstCoordinate = 0; firstCoordinate < detectedBlobHsv.rows(); firstCoordinate++) { for (int secondCoordinate = 0; secondCoordinate < detectedBlobHsv.cols(); secondCoordinate++) { Log.i(TAG, "HAPPY " + Arrays.toString(detectedBlobHsv.get(firstCoordinate, secondCoordinate))); if (Imgproc.pointPolygonTest(largestContour2f, new Point(firstCoordinate, secondCoordinate), false) == -1) { Log.i(TAG, "HAPPY ....................... OUTSIDE"); } } } Highgui.imwrite("/mnt/sdcard/DCIM/processedcontoured.bmp", detectedBlobHsv);// check
編輯:
我這樣做,因爲我需要計算趴在輪廓內像素的平均HSV顏色(即平均HSV顏色最大的紅色斑點)。如果我通過正常的公式計算的ROI detectedBlobHsv
的平均顏色,我會做類似
Scalar averageHsvColor= new Scalar(256);
Scalar sumHsvOfPixels = new Scalar(256);
sumHsvOfPixels = Core.sumElems(detectedBlobHsv);
int numOfPixels = detectedBlobHsv.width() * detectedBlobHsv.height();
for (int channel=0; channel<sumHsvOfPixels.val.length; channel++) {
averageHsvColor = sumHsvOfPixels.val[channel]/numOfPixels;
}
因此就有人在這裏SO(可能嗎?)曾建議我的方式來排除我的輪廓,而在外面的像素背部。我想實現像:
//Giving pixels outside contour of interest an HSV value of `double[]{0,0,0}`, so that they don't affect the computation of `sumHsvOfPixels` while computing average,
//and while keeping track of the number of pixels removed from computation this way, so we can subtract that number from the `$numOfPixels` during computation of average.
int pixelsRemoved = 0;
for (int row=0; row<detectedBlobHsv.rows(); row++) {
for (int col=0; col<detectedBlobHsv.cols(); col++) {
if (Imgproc.pointPolygonTest(largestContour2f, new Point(row, col), false) == -1) {
detectedBlobHsv.put(row, col, new double[]{0,0,0});
pixelsRemoved++;
}
}
}
然後計算像
Scalar averageHsvColor= new Scalar(256);
Scalar sumHsvOfPixels = new Scalar(256);
sumHsvOfPixels = Core.sumElems(detectedBlobHsv); //This will now exclude pixels outside the contour
int numOfPixels = ( detectedBlobHsv.width()*detectedBlobHsv.height() )-pixelsRemoved;
for (int channel=0; channel<sumHsvOfPixels.val.length; channel++) {
averageHsvColor = sumHsvOfPixels.val[channel]/numOfPixels;
}
EDIT 1平均:
往下面的方法結束時,我有創建了一個列表MatOfPoint
s的面具,其中包含最大的只有輪廓。當我把它寫的SD卡,我得到了
我不知道我搞砸了!
private Scalar detectColoredBlob() {
//Highgui.imwrite("/mnt/sdcard/DCIM/rgbaFrame.jpg", rgbaFrame);// check
rgbaFrame = Highgui.imread("/mnt/sdcard/DCIM/rgbaMat4Mask.bmp");
//GIVING A UNIFORM VALUE OF 255 TO THE V CHANNEL OF EACH PIXEL (255 IS THE MAXIMUM VALUE OF V ALLOWED - Simulating a maximum light condition)
for (int firstCoordinate = 0; firstCoordinate < rgbaFrame.rows(); firstCoordinate++) {
for (int secondCoordinate = 0; secondCoordinate < rgbaFrame.cols(); secondCoordinate++) {
double[] pixelChannels = rgbaFrame.get(firstCoordinate, secondCoordinate);
pixelChannels[2] = 255;
rgbaFrame.put(firstCoordinate, secondCoordinate, pixelChannels);
}
}
Mat hsvImage = new Mat();
Imgproc.cvtColor(rgbaFrame, hsvImage, Imgproc.COLOR_BGR2HSV);
Highgui.imwrite("/mnt/sdcard/DCIM/hsvImage.bmp", hsvImage);// check
Mat maskedImage = new Mat();
Core.inRange(hsvImage, new Scalar(0, 100, 100), new Scalar(10, 255, 255), maskedImage);
Highgui.imwrite("/mnt/sdcard/DCIM/maskedImage.bmp", 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(maskedImage, contours, new Mat(), Imgproc.RETR_LIST, Imgproc.CHAIN_APPROX_SIMPLE);
//FINDING THE BIGGEST CONTOUR
// \/ We will 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(i);
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.bmp", detectedBlobRgba);// check
Mat detectedBlobHsv = new Mat();
Imgproc.cvtColor(detectedBlobRgba, detectedBlobHsv, Imgproc.COLOR_BGR2HSV);
Highgui.imwrite("/mnt/sdcard/DCIM/roiHsv.bmp", detectedBlobHsv);// check
List<MatOfPoint> largestContourList = new ArrayList<>();
largestContourList.add(largestContour);
Mat roiWithMask = new Mat(detectedBlobHsv.rows(), detectedBlobHsv.cols(), CvType.CV_8UC3);
roiWithMask.setTo(new Scalar(0,0,0));
Imgproc.drawContours(roiWithMask, largestContourList, 0, new Scalar(0, 255, 255), -1);//TODO Using -1 instead of CV_FILLED.
Highgui.imwrite("/mnt/sdcard/DCIM/roiWithMask.bmp", roiWithMask);// check
// CALCULATING THE AVERAGE COLOR OF THE DETECTED BLOB
// STEP 1:
double [] averageHsvColor = new double[]{0,0,0};
int numOfPixels = 0;
for (int firstCoordinate = 0; firstCoordinate < detectedBlobHsv.rows(); ++firstCoordinate) {
for (int secondCoordinate = 0; secondCoordinate < detectedBlobHsv.cols(); ++secondCoordinate) {
double hue = roiWithMask.get(firstCoordinate, secondCoordinate)[0];
double saturation = roiWithMask.get(firstCoordinate, secondCoordinate)[1];
double value = roiWithMask.get(firstCoordinate, secondCoordinate)[2];
averageHsvColor[0] += hue;
averageHsvColor[1] += saturation;
averageHsvColor[2] += value;
numOfPixels++;
}
}
averageHsvColor[0] /= numOfPixels;
averageHsvColor[1] /= numOfPixels;
averageHsvColor[1] /= numOfPixels;
return new Scalar(averageHsvColor);
}
編輯2:
我糾正我的3信道掩模和由單一信道掩模
Mat roiMask = new Mat(rgbaFrame.rows(), rgbaFrame.cols(), CvType.CV_8UC1);
roiMask.setTo(new Scalar(0));
Imgproc.drawContours(roiMask, largestContourList, 0, new Scalar(255), -1);
,這導致在正確roiMask
:
然後,評論// CALCULATING THE AVERAGE COLOR OF THE DETECTED BLOB
之前,我補充說:
Mat newImageWithRoi = new Mat(rgbaFrame.rows(), rgbaFrame.cols(), CvType.CV_8UC3);
newImageWithRoi.setTo(new Scalar(0, 0, 0));
rgbaFrame.copyTo(newImageWithRoi, roiMask);
Highgui.imwrite("/mnt/sdcard/DCIM/newImageWithRoi.bmp", newImageWithRoi);//check
這導致:
現在又不知如何着手。:s
爲什麼你需要這樣做?一旦你有輪廓或面具,你現在已經有哪些點在裏面了。 – Miki
@Miki請參閱問題中的編輯,我在那裏說明。 – Solace
我_hardly_建議使用'pointPolygonTest':D。看到答案... – Miki