Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/opencv/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/image-processing/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
OpenCV锐化边缘(没有孔的边缘)_Opencv_Image Processing_Opencv Contour - Fatal编程技术网

OpenCV锐化边缘(没有孔的边缘)

OpenCV锐化边缘(没有孔的边缘),opencv,image-processing,opencv-contour,Opencv,Image Processing,Opencv Contour,我正在尝试检测最大/更大的矩形形状,并将边界框绘制到检测到的区域。 在我的用例中,表示矩形形状的对象通常(并非总是)是白色的,背景的颜色也非常类似于白色 在检测轮廓之前,我对图像进行了预处理,以检测出完美的边缘。 我的问题是,我不能完美地检测边缘,即使在模糊和使用“自适应阈值”或“阈值”后,我也有很多噪声 我尝试了不同的方法在不同的光照条件下检测出完美的边缘,但没有成功 如何处理图像以检测轮廓检测的完美边缘(没有孔的边缘) 下面是我正在使用的代码 public static Mat findR

我正在尝试检测最大/更大的矩形形状,并将边界框绘制到检测到的区域。 在我的用例中,表示矩形形状的对象通常(并非总是)是白色的,背景的颜色也非常类似于白色

在检测轮廓之前,我对图像进行了预处理,以检测出完美的边缘。 我的问题是,我不能完美地检测边缘,即使在模糊和使用“自适应阈值”或“阈值”后,我也有很多噪声

我尝试了不同的方法在不同的光照条件下检测出完美的边缘,但没有成功

如何处理图像以检测轮廓检测的完美边缘(没有孔的边缘)

下面是我正在使用的代码

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;

}
公共静态Mat findRectangleX(Mat原件){
Mat src=original.clone();
Mat灰色=新Mat();
Mat二进制=新Mat();
MatOfPoint2f approxCurve;
列表等高线=新的ArrayList();
if(original.type()!=CvType.CV_8U){
Imgproc.cvt颜色(原色、灰色、Imgproc.COLOR\u bgr2灰色);
}否则{
原件。复印件(灰色);
}
高斯模糊(灰色,灰色,新尺寸(5,5),0);
Imgproc.adaptiveThreshold(灰色,二进制,255,Imgproc.ADAPTIVE_THRESH_GAUSSIAN_C,Imgproc.THRESH_binary_INV,11,1);
//Imgproc.阈值(灰色,二进制,0255,Imgproc.THRESH_binary_INV | Imgproc.THRESH_OTSU);
双最大面积=0;
Imgproc.findContours(二进制、等高线、新Mat()、Imgproc.RETR\u列表、Imgproc.CHAIN\u近似\u简单);

对于(int i=0;i我通过计算输入图像的梯度绝对值的近似值,获得了一个非常好的边缘图像

编辑:在我开始工作之前,我将输入图像的大小调整为小5倍。如果您在该图像上使用我的代码,结果会很好。如果您想使我的代码与原始大小的图像配合使用,请执行以下任一操作:

  • 将高斯核大小和sigmas乘以5,或
  • 按系数5对图像进行下采样,执行算法,然后按系数5对结果进行上采样(这应该比第一个选项快得多)
这是我得到的结果:

我的程序依赖于两个关键特性。第一个是转换到适当的颜色空间。HSV颜色空间中的饱和通道是这里的好选择。第二个重要的是梯度绝对值的估计。我使用了sobel算子和一些算法。如果是这样,我可以提供额外的解释没人要求他们

这是我用来获取第一张图像的代码

using namespace std;
using namespace cv;

Mat img_rgb = imread("letter.jpg");

Mat img_hsv;
cvtColor(img_rgb, img_hsv, CV_BGR2HSV);
vector<Mat> channels_hsv;
split(img_hsv, channels_hsv);

Mat channel_s = channels_hsv[1];
GaussianBlur(channel_s, channel_s, Size(9, 9), 2, 2);

Mat imf;
channel_s.convertTo(imf, CV_32FC1, 0.5f, 0.5f);

Mat sobx, soby;
Sobel(imf, sobx, -1, 1, 0);
Sobel(imf, soby, -1, 0, 1);

sobx = sobx.mul(sobx);
soby = soby.mul(soby);

Mat grad_abs_val_approx;
cv::pow(sobx + soby, 0.5, grad_abs_val_approx);

Mat filtered;
GaussianBlur(grad_abs_val_approx, filtered, Size(9, 9), 2, 2);

Scalar mean, stdev;
meanStdDev(filtered, mean, stdev);

Mat thresholded;
cv::threshold(filtered, thresholded, mean.val[0] + stdev.val[0], 1.0, CV_THRESH_TOZERO);

// I scale the image at this point so that it is displayed properly 
imshow("image", thresholded/50);
使用名称空间std;
使用名称空间cv;
Mat img_rgb=imread(“letter.jpg”);
Mat img_hsv;
CVT颜色(img_rgb、img_hsv、CV_BGR2HSV);
矢量通道;
分割(img\U hsv、频道\U hsv);
Mat channel_s=channels_hsv[1];
GaussianBlur(channel_s,channel_s,Size(9,9),2,2);
国际货币基金组织;
渠道转换(国际货币基金组织,CV_32FC1,0.5f,0.5f);
Mat sobx,soby;
Sobel(国际货币基金组织,sobx,-1,1,0);
Sobel(国际货币基金组织,soby,-1,0,1);
sobx=sobx.mul(sobx);
soby=soby.mul(soby);
材料梯度(绝对值)近似值;
cv::pow(sobx+soby,0.5,梯度约为绝对值);
垫过滤;
GaussianBlur(grad_abs_val_近似值,过滤,大小(9,9),2,2);
标量平均值,stdev;
meanstdev(过滤,平均,标准差);
垫阈值;
cv::threshold(过滤、阈值化、平均值[0]+标准偏差值[0],1.0,cv_threshold_至零);
//我在这一点缩放图像,使其正确显示
imshow(“图像”,阈值化/50);
这是我如何计算第二幅图像的:

Mat thresholded_bin;
cv::threshold(filtered, thresholded_bin, mean.val[0] + stdev.val[0], 1.0, CV_THRESH_BINARY);

Mat converted;
thresholded_bin.convertTo(converted, CV_8UC1);

vector<vector<Point>> contours;
findContours(converted, contours, CV_RETR_LIST, CV_CHAIN_APPROX_NONE);

Mat contour_img = Mat::zeros(converted.size(), CV_8UC1);
drawContours(contour_img, contours, -1, 255);

imshow("contours", contour_img);
Mat阈值化_-bin;
cv::threshold(过滤的,阈值化的,平均值[0]+stdev.val[0],1.0,cv\u阈值二进制);
垫转换;
阈值箱转换器(已转换,CV_8UC1);
矢量等值线;
findContours(已转换、等高线、等高线重建列表、等高线链近似值无);
Mat contour_img=Mat::zeros(已转换的.size(),CV_8UC1);
等高线图(等高线图,等高线-1255);
imshow(“轮廓线”,轮廓线);

感谢您的评论和建议。 @NEJC提供的代码工作得很好,涵盖了我80%的用例

然而,它不适用于类似的情况 我不知道为什么

也许有人有想法/线索/解决方案

我继续改进代码,并试图找到一个更通用的解决方案,可以覆盖更多的情况。如果我找到了,我会发布它

无论如何,下面是基于@NEJC解决方案和注释的工作代码

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 sumxy = new Mat();
    Core.add(sobx,soby, sumxy);
    Core.pow(sumxy, 0.5, grad_abs_val_approx);

    sobx.release();
    soby.release();
    sumxy.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_INV);
    Mat converted = new Mat();
    thresholded_bin.convertTo(converted, CV_8UC1);
    */

    Mat converted = new Mat();
    thresholded.convertTo(converted, CV_8UC1);
    return converted;
}
公共静态Mat流程(Mat原件){
Mat src=original.clone();
Mat hsvMat=新Mat();
Mat饱和=新Mat();
Mat sobx=新Mat();
Mat soby=新Mat();
材料梯度(abs)值(val)近似值=新材料();
Imgproc.cvtColor(src、hsvMat、Imgproc.COLOR_BGR2HSV);
列出hsv_频道=新阵列列表(3);
Core.split(hsvMat、hsv_频道);
Mat色调=hsv_频道。获取(0);
Mat sat=hsv_频道。get(1);
Mat val=hsv_通道。获取(2);
高斯模糊(sat,饱和,新尺寸(9,9),2,2);
Mat imf=新Mat();
饱和转换为(imf,CV_32FC1,0.5f,0.5f);
Sobel(国际货币基金组织,sobx,-1,1,0);
Sobel(国际货币基金组织,soby,-1,0,1);
sobx=sobx.mul(sobx);
soby=soby.mul(soby);
Mat sumxy=新Mat();
Core.add(sobx、soby、sumxy);
堆芯功率(sumxy,0.5,梯度绝对值约);
sobx.release();
soby.release();
sumxy.release();;
Mat filtered=新Mat();
Imgproc.GaussianBlur(梯度近似值,过滤,新尺寸(9,9),2,2);
最终MatOfDouble平均值=新MatOfDouble();
最终MatOfDouble stdev=新MatOfDouble();
Core.meanstdev(过滤,平均,标准差);
Mat Threshold=新Mat();
Imgproc.threshold(过滤、阈值化、平均toArray()[0]+stdev.toArray()[0],1.0,Imgproc.threshold_至零);
/*
Mat阈值_bin=新Mat();
Imgproc.threshold(过滤的,阈值化的,平均值toArray()[0]+stdev.toArray()[0],1.0,Imgproc.threshold\u BI
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 sumxy = new Mat();
    Core.add(sobx,soby, sumxy);
    Core.pow(sumxy, 0.5, grad_abs_val_approx);

    sobx.release();
    soby.release();
    sumxy.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_INV);
    Mat converted = new Mat();
    thresholded_bin.convertTo(converted, CV_8UC1);
    */

    Mat converted = new Mat();
    thresholded.convertTo(converted, CV_8UC1);
    return converted;
}