我正在尝试检测最大/较大的矩形形状并绘制边界框到检测区域。在我的用例中,表示矩形形状的对象往往(但并不总是)是白色的,背景也是非常相似的白色。
在检测轮廓之前,我对图像进行了预处理,以便检测完美的边缘。我的问题是,即使在模糊和使用“自适应阈值”或“阈值”之后,我也无法完美地检测到边缘,并且有很多噪声。 我用于轮廓检测的原始图像 我尝试了不同的方法来检测不同光照条件下的完美边缘,但没有成功。
如何处理图像以检测轮廓检测的完美边缘(没有孔洞的边缘)?
下面是我正在使用的代码
我在stackoverflow上搜索了类似的问题并尝试了代码示例,但它们都没有对我起作用。我认为困难在于白色物体和白色背景之间的区别。
如何处理图像以锐化轮廓检测边缘?
如何检测最大/最大的矩形形状并绘制矩形线到检测到的形状中?
//更新于:2017年2月20日
我已经尝试了@ Nejc在下面帖子中提出的解决方案。分割更好了,但我仍然有轮廓中的空洞,并且findcontours无法检测到更大的轮廓。 以下是@ Nejc提供的代码,并转换为java。
在检测轮廓之前,我对图像进行了预处理,以便检测完美的边缘。我的问题是,即使在模糊和使用“自适应阈值”或“阈值”之后,我也无法完美地检测到边缘,并且有很多噪声。 我用于轮廓检测的原始图像 我尝试了不同的方法来检测不同光照条件下的完美边缘,但没有成功。
如何处理图像以检测轮廓检测的完美边缘(没有孔洞的边缘)?
下面是我正在使用的代码
public static Mat findRectangleX(Mat original) {
Mat src = original.clone();
Mat gray = new Mat();
Mat binary = new Mat();
MatOfPoint2f approxCurve;
List<MatOfPoint> contours = new ArrayList<MatOfPoint>();
if (original.type() != CvType.CV_8U) {
Imgproc.cvtColor(original, gray, Imgproc.COLOR_BGR2GRAY);
} else {
original.copyTo(gray);
}
Imgproc.GaussianBlur(gray, gray, new Size(5,5),0);
Imgproc.adaptiveThreshold(gray, binary, 255,Imgproc.ADAPTIVE_THRESH_GAUSSIAN_C,Imgproc.THRESH_BINARY_INV,11, 1);
//Imgproc.threshold(gray, binary,0,255,Imgproc.THRESH_BINARY_INV | Imgproc.THRESH_OTSU);
double maxArea = 0;
Imgproc.findContours(binary, contours, new Mat(),Imgproc.RETR_LIST, Imgproc.CHAIN_APPROX_SIMPLE);
for (int i = 0; i<contours.size();i++) {
MatOfPoint contour = contours.get(i);
MatOfPoint2f temp = new MatOfPoint2f(contour.toArray());
double area = Imgproc.contourArea(contour);
approxCurve = new MatOfPoint2f();
Imgproc.approxPolyDP(temp, approxCurve, Imgproc.arcLength(temp, true) * 0.03, true);
if (approxCurve.total() == 4 ) {
Rect rect = Imgproc.boundingRect(contours.get(i));
Imgproc.rectangle(src, rect.tl(), rect.br(), new Scalar(255, 0, 0, .8), 4);
if(maxArea < area)
maxArea = area;
}
}
Log.v(TAG, "Total contours found : " + contours.size());
Log.v(TAG, "Max area :" + maxArea);
return src;
}
我在stackoverflow上搜索了类似的问题并尝试了代码示例,但它们都没有对我起作用。我认为困难在于白色物体和白色背景之间的区别。
如何处理图像以锐化轮廓检测边缘?
如何检测最大/最大的矩形形状并绘制矩形线到检测到的形状中?
//更新于:2017年2月20日
我已经尝试了@ Nejc在下面帖子中提出的解决方案。分割更好了,但我仍然有轮廓中的空洞,并且findcontours无法检测到更大的轮廓。 以下是@ Nejc提供的代码,并转换为java。
public static Mat process(Mat original){
Mat src = original.clone();
Mat hsvMat = new Mat();
Mat saturation = new Mat();
Mat sobx = new Mat();
Mat soby = new Mat();
Mat grad_abs_val_approx = new Mat();
Imgproc.cvtColor(src, hsvMat, Imgproc.COLOR_BGR2HSV);
List<Mat> hsv_channels = new ArrayList<Mat>(3);
Core.split(hsvMat, hsv_channels);
Mat hue = hsv_channels.get( 0 );
Mat sat = hsv_channels.get( 1 );
Mat val = hsv_channels.get( 2 );
Imgproc.GaussianBlur(sat, saturation, new Size(9, 9), 2, 2);
Mat imf = new Mat();
saturation.convertTo(imf, CV_32FC1, 0.5f, 0.5f);
Imgproc.Sobel(imf, sobx, -1, 1, 0);
Imgproc.Sobel(imf, soby, -1, 0, 1);
sobx = sobx.mul(sobx);
soby = soby.mul(soby);
Mat abs_x = new Mat();
Core.convertScaleAbs(sobx,abs_x);
Mat abs_y = new Mat();
Core.convertScaleAbs(soby,abs_y);
Core.addWeighted(abs_x, 1, abs_y, 1, 0, grad_abs_val_approx);
sobx.release();
soby.release();
Mat filtered = new Mat();
Imgproc.GaussianBlur(grad_abs_val_approx, filtered, new Size(9, 9), 2, 2);
final MatOfDouble mean = new MatOfDouble();
final MatOfDouble stdev = new MatOfDouble();
Core.meanStdDev(filtered, mean, stdev);
Mat thresholded = new Mat();
Imgproc.threshold(filtered, thresholded, mean.toArray()[0] + stdev.toArray()[0], 1.0, Imgproc.THRESH_TOZERO);
/*
Mat thresholded_bin = new Mat();
Imgproc.threshold(filtered, thresholded_bin, mean.toArray()[0] + stdev.toArray()[0], 1.0, Imgproc.THRESH_BINARY);
Mat converted = new Mat();
thresholded_bin.convertTo(converted, CV_8UC1);
*/
return thresholded;
}
这是我运行上面代码后得到的图像:
1)为什么我的翻译代码不能输出与 @Nejc 相同的图像? 应用于相同图像的相同代码应该产生相同的输出吗?
2)在翻译时,我有遗漏了什么吗?
3)为了我理解,为什么我们要在 sobx.mul(sobx) 这条指令中将图像乘以自己?