opencv ओपनसीवी किनारों को छेदने(किनारों के छेद नहीं)




image-processing opencv-contour (2)

मैंने इनपुट छवि के ढाल के निरपेक्ष मूल्य के एक अनुमान को कंप्यूटिंग करके किनारे की एक बहुत अच्छी छवि प्राप्त करने में कामयाब रहा।

संपादित करें: इससे पहले कि मैंने काम करना शुरू किया, मैंने इनपुट छवि को 5x छोटे आकार में बदल दिया। इसे देखने के लिए यहां क्लिक करें! । यदि आप उस छवि पर अपना कोड उपयोग करते हैं, तो परिणाम अच्छे होंगे यदि आप अपना कोड मूल आकार की छवि के साथ अच्छी तरह से काम करना चाहते हैं, तो या तो:

  • गाऊसी कर्नेल आकार और सिगमा 5 से गुणा करें, या
  • कारक 5 से छवि को कम किया जाता है, एल्गोरिथ्म को निष्पादित करता है और फिर कारक 5 का नतीजा उत्पन्न होता है (यह पहले विकल्प की तुलना में बहुत तेजी से काम करना चाहिए)

यह मेरा परिणाम है:

मेरी प्रक्रिया दो प्रमुख विशेषताओं पर निर्भर करती है पहला रंगीन रंग स्थान के लिए एक रूपांतरण है जेरु ल्यूक ने अपने जवाब में कहा , एचएसवी रंग अंतरिक्ष में संतृप्ति चैनल अच्छा विकल्प है। दूसरी महत्वपूर्ण बात, ढाल के पूर्ण मूल्य का अनुमान है। मैं उस उद्देश्य के लिए सोबेल ऑपरेटरों और कुछ अंकगणित का इस्तेमाल किया। अगर कोई उन्हें अनुरोध करता है तो मैं अतिरिक्त स्पष्टीकरण प्रदान कर सकता हूं।

यह पहला कोड प्राप्त करने वाला कोड है I

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);

और इसी तरह मैंने दूसरी छवि की गणना की है:

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);

मैं सबसे बड़ा / बड़ा आयताकार आकार का पता लगाने की कोशिश कर रहा हूं और पता लगाए गए क्षेत्र में बाउंडिंग बॉक्स को खींच रहा हूं। मेरे उपयोग के मामले में, अक्सर (और हमेशा नहीं) आयत आकार का प्रतिनिधित्व करने वाला ऑब्जेक्ट सफेद रंग में होता है और पृष्ठभूमि भी सफेद रंग के समान होता है

आकृतियों का पता लगाने से पहले, मैंने सही किनारे का पता लगाने के लिए छवि को प्रीप्रोसेक किया है मेरी समस्या यह है कि मैं पूरी तरह से किनारों का पता नहीं लगा पा रहा हूं और मुझे धुंधला और 'अनुकूली दहलीज' या 'थ्रेसहोल्ड' का उपयोग करने के बाद भी काफी शोर हैं।

मूल छवि का उपयोग करके मैंने प्रतिरूप का पता लगाया है

मैंने सफलता के बिना अलग प्रकाश स्थिति में सही बढ़त का पता लगाने के लिए अलग-अलग तरीके से कोशिश की है

समोच्च पहचान के लिए सही किनारे (कोई छेद वाले किनारों) का पता लगाने के लिए मैं छवि को कैसे संसाधित कर सकता हूं?

नीचे कोड का उपयोग कर रहा हूं I

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;

}

मुझे स्टैक ओवरफ्लो पर इसी तरह की समस्याएं मिल रही हैं और कोड नमूने आज़माएं लेकिन इनमें से किसी ने मेरे लिए काम किया मुझे लगता है कि मुश्किल सफेद पृष्ठभूमि पर सफेद objet है

समोच्च पहचान के किनारों को तेज करने के लिए मैं छवि को कैसे संसाधित कर सकता हूं?

मैं सबसे बड़ा / बड़ा आयताकार आकार कैसे खोज सकता हूँ और आयत आकार को आकृति में खींच सकता हूं?

// अपडेट किया गया: 20/02/2017

मैंने नीचे दी गई पोस्ट में @एनजेसी द्वारा सुझाए गए समाधान की कोशिश की है। विभाजन बेहतर है, लेकिन मेरे पास समोच्च में छेद हैं और बड़े अंतर समोच्च का पता लगाने में खोजकर्ताएं विफल हैं। नीचे एनईजेसी द्वारा प्रदान किया गया कोड और जावा में अनुवाद किया गया है।

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) क्यों मेरा अनुवादित कोड @जेजेसी की तरह ही छवि नहीं दिखाता? एक ही छवि पर एक ही कोड लागू एक ही उत्पादन का उत्पादन करना चाहिए?

2) क्या मुझे अनुवाद करते समय कुछ याद आया?

3) मेरी समझ के लिए, हमने इस अनुदेश में sobx = sobx.mul (sobx) में अपने आप में छवि क्यों बढ़ाई है; ?


आपके टिप्पणियों और सुझाव के लिए धन्यवाद @ एनईजेसी द्वारा प्रदान किया गया कोड पूरी तरह से कार्य करता है और मेरे उपयोग के 80% केस को कवर करता है।

फिर भी, यह इसी तरह के केस के साथ काम नहीं करता जैसा कि इस मामले को वर्तमान कोड द्वारा हल नहीं किया गया और मुझे नहीं पता कि क्यों

शायद किसी के पास एक विचार / सुराग / समाधान है?

मैं कोड को सुधारना जारी रखता हूं और अधिक सामान्य समाधान ढूंढने का प्रयास करता हूं जो अधिक केस को कवर कर सकता है। अगर मैं कभी भी मुझे मिल सकता है तो मैं इसे पोस्ट करूंगा

किसी भी मामले में, एनईजेसी समाधान और नोट्स पर आधारित काम कोड नीचे है।

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;
}






opencv-contour