OpenCV C ++ / Obj-C: कागज की एक शीट का पता लगाना / स्क्वायर डिटेक्शन


178

मैंने अपने परीक्षण एप्लिकेशन में OpenCV वर्ग-पहचान का उदाहरण सफलतापूर्वक लागू किया है, लेकिन अब आउटपुट को फ़िल्टर करने की आवश्यकता है, क्योंकि यह काफी गड़बड़ है - या क्या मेरा कोड गलत है?

मैं तिरछी कटौती (जैसे कि ) और आगे की प्रक्रिया के लिए कागज के चार कोनों में दिलचस्पी रखता हूं ...

इनपुट आउटपुट: इनपुट आउटपुट

मूल छवि:

क्लिक

कोड:

double angle( cv::Point pt1, cv::Point pt2, cv::Point pt0 ) {
    double dx1 = pt1.x - pt0.x;
    double dy1 = pt1.y - pt0.y;
    double dx2 = pt2.x - pt0.x;
    double dy2 = pt2.y - pt0.y;
    return (dx1*dx2 + dy1*dy2)/sqrt((dx1*dx1 + dy1*dy1)*(dx2*dx2 + dy2*dy2) + 1e-10);
}

- (std::vector<std::vector<cv::Point> >)findSquaresInImage:(cv::Mat)_image
{
    std::vector<std::vector<cv::Point> > squares;
    cv::Mat pyr, timg, gray0(_image.size(), CV_8U), gray;
    int thresh = 50, N = 11;
    cv::pyrDown(_image, pyr, cv::Size(_image.cols/2, _image.rows/2));
    cv::pyrUp(pyr, timg, _image.size());
    std::vector<std::vector<cv::Point> > contours;
    for( int c = 0; c < 3; c++ ) {
        int ch[] = {c, 0};
        mixChannels(&timg, 1, &gray0, 1, ch, 1);
        for( int l = 0; l < N; l++ ) {
            if( l == 0 ) {
                cv::Canny(gray0, gray, 0, thresh, 5);
                cv::dilate(gray, gray, cv::Mat(), cv::Point(-1,-1));
            }
            else {
                gray = gray0 >= (l+1)*255/N;
            }
            cv::findContours(gray, contours, CV_RETR_LIST, CV_CHAIN_APPROX_SIMPLE);
            std::vector<cv::Point> approx;
            for( size_t i = 0; i < contours.size(); i++ )
            {
                cv::approxPolyDP(cv::Mat(contours[i]), approx, arcLength(cv::Mat(contours[i]), true)*0.02, true);
                if( approx.size() == 4 && fabs(contourArea(cv::Mat(approx))) > 1000 && cv::isContourConvex(cv::Mat(approx))) {
                    double maxCosine = 0;

                    for( int j = 2; j < 5; j++ )
                    {
                        double cosine = fabs(angle(approx[j%4], approx[j-2], approx[j-1]));
                        maxCosine = MAX(maxCosine, cosine);
                    }

                    if( maxCosine < 0.3 ) {
                        squares.push_back(approx);
                    }
                }
            }
        }
    }
    return squares;
}

EDIT 17/08/2012:

छवि पर अंकित वर्गों को खींचने के लिए इस कोड का उपयोग करें:

cv::Mat debugSquares( std::vector<std::vector<cv::Point> > squares, cv::Mat image )
{
    for ( int i = 0; i< squares.size(); i++ ) {
        // draw contour
        cv::drawContours(image, squares, i, cv::Scalar(255,0,0), 1, 8, std::vector<cv::Vec4i>(), 0, cv::Point());

        // draw bounding rect
        cv::Rect rect = boundingRect(cv::Mat(squares[i]));
        cv::rectangle(image, rect.tl(), rect.br(), cv::Scalar(0,255,0), 2, 8, 0);

        // draw rotated rect
        cv::RotatedRect minRect = minAreaRect(cv::Mat(squares[i]));
        cv::Point2f rect_points[4];
        minRect.points( rect_points );
        for ( int j = 0; j < 4; j++ ) {
            cv::line( image, rect_points[j], rect_points[(j+1)%4], cv::Scalar(0,0,255), 1, 8 ); // blue
        }
    }

    return image;
}


1
मुझे लगता है कि यदि आप इसे अधिक उपयुक्त समझते हैं, तो आप प्रश्न के शीर्षक को कागज की शीट का पता लगाने जैसे कुछ के लिए समायोजित कर सकते हैं ।
कर्लफिलिप

1
@moosgummi मुझे वही कार्यक्षमता दिख रही है जिसे आपने लागू किया है अर्थात "कैप्चर / डॉक्यूमेंट के कॉर्नर का पता लगाएं"। आपने यह कैसे हासिल किया? क्या मैं अपने iPhone एप्लिकेशन के भीतर OpenCV का उपयोग कर पाऊंगा? कृपया मुझे इसके लिए कुछ बेहतर उपाय
सुझाएं

1
क्या आपने कभी OpenCV के साथ कुछ किया है? किसी भी आवेदन?
कार्लफिलिप

6
यह ध्यान देने योग्य है कि ध्वज CV_RETR_EXTERNAL का उपयोग तब किया जा सकता है जब किसी बंद आकृति के अंदर सभी आकृति को अस्वीकार करने के लिए काउंटर्स का पता लगा रहे हों।
mehfoos याकूब

जवाबों:


162

यह Stackoverflow में एक आवर्ती विषय है और चूंकि मैं एक प्रासंगिक कार्यान्वयन को खोजने में असमर्थ था, इसलिए मैंने चुनौती स्वीकार करने का निर्णय लिया।

मैंने OpenCV में मौजूद चौकों के डेमो में कुछ बदलाव किए और नीचे दिया गया C ++ कोड छवि में कागज की एक शीट का पता लगाने में सक्षम है:

void find_squares(Mat& image, vector<vector<Point> >& squares)
{
    // blur will enhance edge detection
    Mat blurred(image);
    medianBlur(image, blurred, 9);

    Mat gray0(blurred.size(), CV_8U), gray;
    vector<vector<Point> > contours;

    // find squares in every color plane of the image
    for (int c = 0; c < 3; c++)
    {
        int ch[] = {c, 0};
        mixChannels(&blurred, 1, &gray0, 1, ch, 1);

        // try several threshold levels
        const int threshold_level = 2;
        for (int l = 0; l < threshold_level; l++)
        {
            // Use Canny instead of zero threshold level!
            // Canny helps to catch squares with gradient shading
            if (l == 0)
            {
                Canny(gray0, gray, 10, 20, 3); // 

                // Dilate helps to remove potential holes between edge segments
                dilate(gray, gray, Mat(), Point(-1,-1));
            }
            else
            {
                    gray = gray0 >= (l+1) * 255 / threshold_level;
            }

            // Find contours and store them in a list
            findContours(gray, contours, CV_RETR_LIST, CV_CHAIN_APPROX_SIMPLE);

            // Test contours
            vector<Point> approx;
            for (size_t i = 0; i < contours.size(); i++)
            {
                    // approximate contour with accuracy proportional
                    // to the contour perimeter
                    approxPolyDP(Mat(contours[i]), approx, arcLength(Mat(contours[i]), true)*0.02, true);

                    // Note: absolute value of an area is used because
                    // area may be positive or negative - in accordance with the
                    // contour orientation
                    if (approx.size() == 4 &&
                            fabs(contourArea(Mat(approx))) > 1000 &&
                            isContourConvex(Mat(approx)))
                    {
                            double maxCosine = 0;

                            for (int j = 2; j < 5; j++)
                            {
                                    double cosine = fabs(angle(approx[j%4], approx[j-2], approx[j-1]));
                                    maxCosine = MAX(maxCosine, cosine);
                            }

                            if (maxCosine < 0.3)
                                    squares.push_back(approx);
                    }
            }
        }
    }
}

इस प्रक्रिया को निष्पादित करने के बाद, कागज की शीट सबसे बड़ा वर्ग होगा vector<vector<Point> >:

opencv पेपर शीट का पता लगाना

मैं आपको सबसे बड़ा वर्ग खोजने के लिए फ़ंक्शन लिखने दे रहा हूं। ;)


4
इसलिए मैं स्रोत नियंत्रण का उपयोग करता हूं। कोड के लिए सबसे छोटा आकस्मिक संशोधन आसानी से खोजा जा सकता है। यदि आपने कुछ भी नहीं बदला है, तो अन्य छवियों के साथ परीक्षण करने का प्रयास करें और अंत में opencile को पुनर्स्थापित / पुनः इंस्टॉल करें।
कार्लफिलिप

2
OpenCV सभी प्लेटफार्मों (Win / Linux / Mac / iPhone / ...) के लिए बहुत समान है। अंतर यह है कि कुछ ने OpenCV के GPU मॉड्यूल का समर्थन नहीं किया है। क्या आपने पहले से ही iOS के लिए OpenCV का निर्माण किया है ? क्या आप इसका परीक्षण करने में सक्षम थे? मुझे लगता है कि ये ऐसे प्रश्न हैं जिनका आपको अधिक उन्नत प्रयास करने से पहले उत्तर देने की आवश्यकता है। बच्चे के कदम!
कार्लफिलिप

1
@Klphillip मैंने इस कोड का परीक्षण किया और मैं स्पष्ट रूप से पेपर का पता लगाने में सक्षम था, लेकिन इसमें इतना समय लगता है। क्या कोड वास्तव में भारी है? SayText नाम से एक ऐप है जहां यह पता वीडियो स्ट्रीम से रियल-टाइम में होता है। यह कोड वास्तविक समय के लिए अव्यावहारिक होगा, क्या मैं सही हूं?
अलंधुलुसी

1
शायद। यह एक अकादमिक उत्तर है, जो उद्योग के लिए बहुत व्यावहारिक नहीं है। आपके द्वारा प्रयास किए गए काउंटर की परिभाषा के साथ शुरुआत करने वाले सभी प्रकार के अनुकूलन हो सकते हैं for (int c = 0; c < 3; c++), जो छवि के प्रत्येक चैनल पर पुनरावृति करने के लिए जिम्मेदार है। उदाहरण के लिए, आप इसे केवल एक चैनल पर पुनरावृत्त करने के लिए सेट कर सकते हैं :) मत भूलना।
कर्लफिलिप

3
@SilentPro angle()एक सहायक कार्य है । जैसा कि उत्तर में कहा गया है, यह कोड OpenCV में मौजूद नमूनों / cpp / squares.cpp पर आधारित है ।
कार्लफिलिप

40

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

यहाँ मैं आपकी नमूना छवि और कुछ अन्य छवि के साथ प्राप्त करता हूं, जो मुझे मिली कागज की एक शीट के साथ है:

यहां छवि विवरण दर्ज करें यहां छवि विवरण दर्ज करें

माध्य फ़िल्टर का उपयोग अब, ग्रेस्केल, छवि से मामूली विवरण निकालने के लिए किया जाता है। यह संभवतः वाइटिश पेपर के अंदर की पतली रेखाओं को हटा देगा, जो अच्छा है क्योंकि तब आप छोटे जुड़े घटकों के साथ समाप्त हो जाएंगे जिन्हें त्यागना आसान है। माध्यिका के बाद, एक रूपात्मक ढाल (बस dilation- erosion) लागू करें और ओत्सु द्वारा परिणाम को द्विगुणित करें। रूपात्मक ढाल मजबूत किनारों को रखने के लिए एक अच्छी विधि है, इसका अधिक उपयोग किया जाना चाहिए। फिर, चूंकि यह ढाल समोच्च चौड़ाई में वृद्धि करेगा, एक रूपात्मक थिनिंग लागू करेगा। अब आप छोटे घटकों को त्याग सकते हैं।

इस बिंदु पर, यहाँ वही है जिसकी ऊपर की दाईं छवि है (नीले बहुभुज को खींचने से पहले), बाईं ओर नहीं दिखाया गया है क्योंकि एकमात्र शेष घटक वह है जो कागज का वर्णन करता है:

यहां छवि विवरण दर्ज करें

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

संदर्भ के लिए, यहाँ गणितज्ञ में एक नमूना कोड दिया गया है:

f = Import["http://thwartedglamour.files.wordpress.com/2010/06/my-coffee-table-1-sa.jpg"]
f = ImageResize[f, ImageDimensions[f][[1]]/4]
g = MedianFilter[ColorConvert[f, "Grayscale"], 2]
h = DeleteSmallComponents[Thinning[
     Binarize[ImageSubtract[Dilation[g, 1], Erosion[g, 1]]]]]
convexvert = ComponentMeasurements[SelectComponents[
     h, {"ConvexArea", "BoundingBoxArea"}, #1 / #2 > 0.7 &], 
     "ConvexVertices"][[All, 2]]
(* To visualize the blue polygons above: *)
Show[f, Graphics[{EdgeForm[{Blue, Thick}], RGBColor[0, 0, 1, 0.5], 
     Polygon @@ convexvert}]]

यदि ऐसी विभिन्न परिस्थितियाँ हैं जहाँ पेपर की आयत इतनी अच्छी तरह से परिभाषित नहीं है, या दृष्टिकोण इसे अन्य आकृतियों के साथ भ्रमित करता है - ये स्थितियाँ विभिन्न कारणों से हो सकती हैं, लेकिन एक सामान्य कारण खराब छवि अधिग्रहण है - फिर पूर्व संयोजन की कोशिश करें कागज में वर्णित काम के साथ-साथ "रेक्टेंगल डिटेक्शन ऑन द विंडोड हूप ट्रांसफॉर्म" के साथ-साथ कदम बढ़ाते हुए।


1
क्या आपके और उसके ऊपर (यानी @Klphilip के उत्तर) के कार्यान्वयन में कोई बड़ा अंतर है? मुझे खेद है कि मुझे कोई तेज़ नज़र नहीं मिला (3 चैनल -1 चैनल और गणितज्ञ-ओपनसीवी को छोड़कर)।
आबिद रहमान के

2
@AbidRahmanK हाँ, वहाँ हैं .. मैं शुरू करने के लिए न तो "कई थ्रेसहोल्ड" का उपयोग नहीं करता। अन्य अंतर हैं, लेकिन आपकी टिप्पणी के लहजे से मेरी टिप्पणी पर कोई भी प्रयास करना व्यर्थ लगता है।
mmgp

1
मुझे लगता है कि आप दोनों पहले किनारों को ढूंढते हैं, और यह निर्धारित करते हैं कि कौन सा किनारा वर्ग है। किनारों को खोजने के लिए, आप लोग विभिन्न तरीकों का उपयोग करते हैं। वह कैनी का उपयोग करता है, आप कुछ फैलाव-क्षरण का उपयोग करते हैं। और "कई थ्रेसहोल्ड", हो सकता है कि वह OpenCV के नमूनों से मिले, जिसका इस्तेमाल वर्गों को खोजने के लिए किया गया था। मुख्य बात यह है, मुझे लगा कि समग्र अवधारणा समान है। "किनारों का पता लगाएं और वर्ग का पता लगाएं"। और मैंने इसे पूरी ईमानदारी से पूछा, मुझे नहीं पता कि आपको मेरी टिप्पणी से "टोन" क्या मिला, या आप (क्या समझा / गलत समझा गया)। इसलिए यदि आपको लगता है कि यह सवाल ईमानदार है, तो मैं अन्य मतभेदों को जानना चाहूंगा। अन्यथा मेरी टिप्पणियों को त्याग दें।
आबिद रहमान के

1
@AbidRahmanK बेशक अवधारणा समान है, कार्य समान है। माध्य फ़िल्टरिंग का उपयोग किया जा रहा है, थिनिंग का उपयोग किया जा रहा है, मुझे इस बात से कोई फ़र्क नहीं पड़ता है कि उसने कई थ्रेसहोल्ड आइडिया कहाँ से लिए हैं - इसका उपयोग यहाँ नहीं किया गया है (इस प्रकार यह अंतर कैसे नहीं हो सकता?), यहाँ इमेज का आकार बदल दिया गया है, घटक माप अलग हैं। "कुछ फैलाव-क्षरण" बाइनरी किनारों को नहीं देता है, उसके लिए ओत्सु का उपयोग किया जाता है। यह उल्लेख करना व्यर्थ है, कोड है।
19

1
के। धन्यवाद। जवाब मिल गया। Concept is the same। (मैंने कभी गणितज्ञ का उपयोग नहीं किया, इसलिए मैं कोड को नहीं समझ सकता।) और आपके द्वारा बताए गए मतभेद मतभेद हैं, लेकिन एक अलग दृष्टिकोण या प्रमुख नहीं। यदि आप अभी भी उदाहरण के लिए, यह जाँचते हैं:
आबिद रहमान के

14

खैर, मुझे देर हो गई।


आपकी छवि में, पेपर है white, जबकि पृष्ठभूमि है colored। इसलिए, यह पता लगाना बेहतर है कि पेपर किस Saturation(饱和度)चैनल में है HSV color spaceसबसे पहले wiki HSL_and_HSV का संदर्भ लें । फिर मैं एक इमेज में इस डिटेक्ट कलर्ड सेगमेंट में अपने जवाब से सबसे ज्यादा आइडिया कॉपी करूंगा ।


मुख्य चरण:

  1. में पढ़ा BGR
  2. छवि bgrको hsvअंतरिक्ष से परिवर्तित करें
  3. थ्रेसहोल्ड एस चैनल
  4. तब अधिकतम बाहरी समोच्च लगता है (या करना Canny, या HoughLinesके रूप में आप की तरह, मैं चुन findContoursकोनों पाने के लिए), लगभग।

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

यहां छवि विवरण दर्ज करें


पायथन कोड (पायथन 3.5 + ओपनसीवी 3.3):

#!/usr/bin/python3
# 2017.12.20 10:47:28 CST
# 2017.12.20 11:29:30 CST

import cv2
import numpy as np

##(1) read into  bgr-space
img = cv2.imread("test2.jpg")

##(2) convert to hsv-space, then split the channels
hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
h,s,v = cv2.split(hsv)

##(3) threshold the S channel using adaptive method(`THRESH_OTSU`) or fixed thresh
th, threshed = cv2.threshold(s, 50, 255, cv2.THRESH_BINARY_INV)

##(4) find all the external contours on the threshed S
#_, cnts, _ = cv2.findContours(threshed, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
cnts = cv2.findContours(threshed, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)[-2]

canvas  = img.copy()
#cv2.drawContours(canvas, cnts, -1, (0,255,0), 1)

## sort and choose the largest contour
cnts = sorted(cnts, key = cv2.contourArea)
cnt = cnts[-1]

## approx the contour, so the get the corner points
arclen = cv2.arcLength(cnt, True)
approx = cv2.approxPolyDP(cnt, 0.02* arclen, True)
cv2.drawContours(canvas, [cnt], -1, (255,0,0), 1, cv2.LINE_AA)
cv2.drawContours(canvas, [approx], -1, (0, 0, 255), 1, cv2.LINE_AA)

## Ok, you can see the result as tag(6)
cv2.imwrite("detected.png", canvas)

संबंधित उत्तर:

  1. OpenCV का उपयोग करके छवि में रंगीन पैच का पता कैसे लगाया जाए?
  2. OpenCV का उपयोग करके रंगीन पृष्ठभूमि पर बढ़त का पता लगाना
  3. OpenCV C ++ / Obj-C: कागज की एक शीट का पता लगाना / स्क्वायर डिटेक्शन
  4. विभिन्न OpenCV संस्करणों में `cv2.findContours` का उपयोग कैसे करें?

मैंने एस स्पेस का उपयोग करने की कोशिश की लेकिन फिर भी सफल नहीं हो सका। इसे देखें: stackoverflow.com/questions/50699893/…
hchouhan02

3

आपको एक घुमाए गए आयत के बजाय एक चतुर्भुज चाहिए। RotatedRectआपको गलत परिणाम देगा। इसके अलावा, आप एक परिप्रेक्ष्य प्रक्षेपण की आवश्यकता होगी।

मूल रूप से जो किया जाना चाहिए वह है:

  • सभी बहुभुज खंडों के माध्यम से लूप करें और उन लोगों को कनेक्ट करें जो लगभग समान हैं।
  • उन्हें क्रमबद्ध करें ताकि आपके पास 4 सबसे बड़े लाइन सेगमेंट हों।
  • उन पंक्तियों को इंटरसेक्ट करें और आपके पास 4 सबसे अधिक संभावना वाले कोने हैं।
  • कोने के बिंदुओं से एकत्रित परिप्रेक्ष्य और ज्ञात वस्तु के पहलू अनुपात पर मैट्रिक्स को बदलना।

मैंने एक वर्ग लागू किया Quadrangleजो चतुष्कोण रूपांतरण के लिए समोच्च का ख्याल रखता है और इसे सही परिप्रेक्ष्य में बदल देगा।

यहां एक कार्यान्‍वयन कार्य देखिए: जावा ओपनसीवी एक समोच्च की मेज़बानी कर रहा है


1

एक बार जब आप दस्तावेज़ के बाउंडिंग बॉक्स का पता लगा लेते हैं, तो आप छवि के ऊपर-नीचे पक्षियों की आंखों को देखने के लिए चार-बिंदु परिप्रेक्ष्य परिवर्तन कर सकते हैं । यह तिरछा को ठीक करेगा और केवल वांछित वस्तु को अलग करेगा।


इनपुट छवि:

ज्ञात पाठ वस्तु

पाठ दस्तावेज़ का टॉप-डाउन दृश्य

कोड

from imutils.perspective import four_point_transform
import cv2
import numpy

# Load image, grayscale, Gaussian blur, Otsu's threshold
image = cv2.imread("1.png")
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
blur = cv2.GaussianBlur(gray, (7,7), 0)
thresh = cv2.threshold(blur, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)[1]

# Find contours and sort for largest contour
cnts = cv2.findContours(thresh, cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)
cnts = cnts[0] if len(cnts) == 2 else cnts[1]
cnts = sorted(cnts, key=cv2.contourArea, reverse=True)
displayCnt = None

for c in cnts:
    # Perform contour approximation
    peri = cv2.arcLength(c, True)
    approx = cv2.approxPolyDP(c, 0.02 * peri, True)
    if len(approx) == 4:
        displayCnt = approx
        break

# Obtain birds' eye view of image
warped = four_point_transform(image, displayCnt.reshape(4, 2))

cv2.imshow("thresh", thresh)
cv2.imshow("warped", warped)
cv2.imshow("image", image)
cv2.waitKey()

-1

कागज की शीट का पता लगाना थोड़े पुराने स्कूल है। यदि आप तिरछी पहचान से निपटना चाहते हैं तो बेहतर है कि आप टेक्स्ट लाइन डिटेक्शन के लिए सीधे लक्ष्य बनाएं। इससे आपको एक्सट्रीम लेफ्ट, राइट, टॉप और बॉटम मिलेगा। यदि आप नहीं चाहते हैं तो छवि में किसी भी ग्राफिक्स को छोड़ दें और फिर सबसे अधिक होने वाली कोण सीमा या बल्कि कोण को खोजने के लिए टेक्स्ट लाइन सेगमेंट पर कुछ आंकड़े दें। यह है कि आप एक अच्छे तिरछा कोण को कैसे छोटा करेंगे। अब इसके बाद आप इन मापदंडों को तिरछा कोण और चरम सीमा तक डेस्क करते हैं और छवि को काटते हैं जो आवश्यक है।

वर्तमान छवि आवश्यकता के अनुसार, यदि आप CV_RETR_IST के बजाय CV_RETR_EXTERNAL को आज़माएँ तो बेहतर है।

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

रैंडम वन कम विपरीत अंतर परिदृश्यों के साथ काम करेंगे, उदाहरण के लिए मोटे तौर पर सफेद पृष्ठभूमि पर श्वेत पत्र।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.