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

แก้ไข 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
ฉันคิดว่าคุณสามารถปรับชื่อของคำถามสำหรับบางอย่างเช่นการตรวจจับแผ่นกระดาษหากคุณคิดว่าเหมาะสมกว่า
karlphillip

1
@moosgummi ฉันต้องการฟังก์ชั่นเดียวกับที่คุณใช้งานเช่น "ตรวจจับมุมของเอกสาร / ภาพที่บันทึก" คุณจะทำสิ่งนี้ได้อย่างไร? ฉันจะสามารถใช้ OpenCV ภายในแอปพลิเคชัน iPhone ของฉันได้หรือไม่ กรุณาแนะนำผมบางวิธีที่ดีกว่าที่จะมี ..
Ajay Sharma

1
คุณเคยทำอะไรกับ OpenCV บ้างไหม? แอปพลิเคชันใด ๆ เลย?
karlphillip

6
เป็นที่น่าสังเกตว่าสามารถใช้ค่าสถานะ CV_RETR_EXTERNAL เมื่อค้นหา countours เพื่อปฏิเสธรูปทรงทั้งหมดที่อยู่ในรูปทรงปิด
mehfoos yacoob

คำตอบ:


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
นั่นเป็นเหตุผลที่ฉันใช้การควบคุมแหล่งที่มา การปรับเปลี่ยนรหัสโดยไม่ตั้งใจน้อยที่สุดสามารถค้นพบได้ง่าย หากคุณไม่ได้เปลี่ยนอะไรลองทดสอบกับภาพอื่น ๆ และในที่สุดก็คอมไพล์ใหม่ / ติดตั้ง opencv
karlphillip

2
OpenCV ค่อนข้างเหมือนกันสำหรับทุกแพลตฟอร์ม (Win / Linux / Mac / iPhone / ... ) ความแตกต่างคือบางคนไม่รองรับโมดูล GPU ของ OpenCV คุณสร้าง OpenCV สำหรับ iOS แล้วหรือยัง คุณสามารถทดสอบได้หรือไม่ ฉันคิดว่านี่เป็นคำถามที่คุณต้องตอบก่อนลองทำอะไรขั้นสูงขึ้น ก้าวย่างของทารก!
karlphillip

1
@karlphillip ฉันทดสอบโค้ดนี้และฉันสามารถตรวจจับกระดาษได้ชัดเจน แต่ใช้เวลานานมาก รหัสหนักมากจริง ๆ หรือ มีแอพที่ชื่อว่า SayText ซึ่งการตรวจจับนี้เกิดขึ้นแบบเรียลไทม์จากสตรีมวิดีโอ รหัสนี้จะใช้ไม่ได้ตามเวลาจริงใช่ไหม?
alandalusi

1
อาจ. นี่เป็นคำตอบเชิงวิชาการไม่ใช่ภาคปฏิบัติสำหรับอุตสาหกรรม มีการเพิ่มประสิทธิภาพทุกประเภทที่คุณสามารถลองได้โดยเริ่มจากคำจำกัดความของตัวนับที่ตั้งอยู่ที่for (int c = 0; c < 3; c++)ซึ่งรับผิดชอบในการวนซ้ำในทุกช่องทางของภาพ ตัวอย่างเช่นคุณสามารถตั้งค่าให้วนซ้ำได้ในช่องเดียวเท่านั้น :) อย่าลืมโหวต
karlphillip

3
@SilentPro angle()เป็นฟังก์ชั่นผู้ช่วย ตามที่ระบุไว้ในคำตอบรหัสนี้ขึ้นอยู่กับตัวอย่าง / cpp / squares.cpp ที่มีอยู่ใน OpenCV
karlphillip

40

หากไม่มีข้อกำหนดอื่นที่ไม่ได้ระบุไว้ฉันเพียงแค่แปลงภาพสีของคุณเป็นสีเทาและทำงานกับสิ่งนั้นเท่านั้น (ไม่จำเป็นต้องทำงานกับ 3 ช่องสัญญาณความคมชัดสูงเกินไปแล้ว) นอกจากนี้หากมีปัญหาบางอย่างเกี่ยวกับการปรับขนาดฉันจะทำงานกับรูปภาพที่มีการลดขนาดเนื่องจากขนาดค่อนข้างใหญ่และขนาดจะไม่เพิ่มปัญหาใด ๆ ที่จะแก้ไข จากนั้นในที่สุดปัญหาของคุณจะได้รับการแก้ไขด้วยตัวกรองมัธยฐานเครื่องมือสัณฐานวิทยาขั้นพื้นฐานและสถิติ (ส่วนใหญ่สำหรับ Otsu thresholding ซึ่งได้ทำเพื่อคุณแล้ว)

นี่คือสิ่งที่ฉันได้จากภาพตัวอย่างของคุณและภาพอื่น ๆ ที่มีแผ่นกระดาษที่ฉันพบ:

ป้อนคำอธิบายรูปภาพที่นี่ ป้อนคำอธิบายรูปภาพที่นี่

ตัวกรองค่ามัธยฐานใช้เพื่อลบรายละเอียดเล็กน้อยจากภาพระดับสีเทาในขณะนี้ มันอาจจะลบเส้นบาง ๆ ในกระดาษสีขาวซึ่งเป็นสิ่งที่ดีเพราะจากนั้นคุณจะจบลงด้วยชิ้นส่วนเล็ก ๆ ที่เชื่อมต่อซึ่งง่ายต่อการทิ้ง หลังจากค่ามัธยฐานให้ใช้การไล่ระดับสีทางสัณฐานวิทยา (เพียงdilation-erosion ) และทำการสรุปผลโดย Otsu การไล่ระดับสีทางสัณฐานวิทยาเป็นวิธีที่ดีในการรักษาความแข็งแรงของขอบควรใช้มากกว่านี้ จากนั้นเนื่องจากการไล่ระดับสีนี้จะเพิ่มความกว้างของเส้นโครงร่างให้ใช้การทำให้ผอมบางทางสัณฐานวิทยา ตอนนี้คุณสามารถละทิ้งส่วนประกอบเล็ก ๆ

ณ จุดนี้นี่คือสิ่งที่เรามีกับภาพด้านบน (ก่อนที่จะวาดรูปหลายเหลี่ยมสีฟ้า) ส่วนที่เหลือจะไม่แสดงเพราะองค์ประกอบที่เหลือเพียงอย่างเดียวคือสิ่งที่อธิบายถึงกระดาษ:

ป้อนคำอธิบายรูปภาพที่นี่

จากตัวอย่างตอนนี้ปัญหาที่เหลือเพียงอย่างเดียวคือการแยกความแตกต่างระหว่างส่วนประกอบที่มีลักษณะเหมือนรูปสี่เหลี่ยมผืนผ้าและอื่น ๆ ที่ไม่ได้ทำ นี่เป็นเรื่องของการกำหนดอัตราส่วนระหว่างพื้นที่ของตัวถังนูนที่มีรูปร่างและพื้นที่ของกล่องขอบเขต อัตราส่วน 0.7 ใช้งานได้ดีสำหรับตัวอย่างเหล่านี้ อาจเป็นกรณีที่คุณต้องทิ้งส่วนประกอบที่อยู่ในกระดาษ แต่ไม่ใช่ในตัวอย่างเหล่านี้โดยใช้วิธีนี้ (อย่างไรก็ตามการทำขั้นตอนนี้ควรง่ายมากโดยเฉพาะอย่างยิ่งเพราะสามารถทำได้ผ่าน OpenCV โดยตรง)

สำหรับการอ้างอิงนี่คือตัวอย่างรหัสใน Mathematica:

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

หากมีสถานการณ์ที่หลากหลายมากขึ้นซึ่งรูปสี่เหลี่ยมผืนผ้าของกระดาษไม่ได้กำหนดไว้อย่างดีหรือวิธีการทำให้สับสนกับรูปร่างอื่น ๆ - สถานการณ์เหล่านี้อาจเกิดขึ้นเนื่องจากเหตุผลต่าง ๆ แต่สาเหตุที่พบบ่อยคือการได้มาซึ่งภาพที่ไม่ดี - ลองรวม - ขั้นตอนการประมวลผลกับงานที่อธิบายไว้ในกระดาษ "การตรวจจับสี่เหลี่ยมผืนผ้าตามการแปลง Hough แบบหน้าต่าง"


1
มีความแตกต่างที่สำคัญในการดำเนินงานของคุณและคนข้างต้น (เช่นคำตอบของ @karlphilip)? ฉันขอโทษที่ฉันไม่สามารถหาดูได้อย่างรวดเร็ว (ยกเว้นช่อง 3 ช่อง -1 และ Mathematica-OpenCV)
Abid Rahman K

2
@AbidRahmanK ใช่มี .. ฉันไม่ได้ใช้แสนอร่อยไม่ได้เริ่มต้นด้วย "หลายเกณฑ์" มีความแตกต่างอื่น ๆ แต่ด้วยน้ำเสียงของความคิดเห็นของคุณมันดูเหมือนไม่มีจุดหมายที่จะใช้ความพยายามของฉันเอง
mmgp

1
ฉันเห็นคุณทั้งคู่เจอขอบก่อนแล้วตัดสินว่าขอบไหนเป็นรูปสี่เหลี่ยม สำหรับการค้นหาขอบคุณคนใช้วิธีการต่าง ๆ เขาใช้แสนรู้คุณใช้การขยายการกัดเซาะ และ "หลายเกณฑ์" เขาอาจจะได้รับจากตัวอย่างของ OpenCV เคยใช้หาสแควร์ส สิ่งสำคัญคือฉันรู้สึกว่าแนวคิดโดยรวมเหมือนกัน "ค้นหาขอบและตรวจจับจตุรัส" และฉันถามด้วยความจริงใจฉันไม่รู้ว่า "น้ำเสียง" ที่คุณได้รับจากความคิดเห็นของฉันหรือสิ่งที่คุณ (เข้าใจ / เข้าใจผิด) ดังนั้นหากคุณรู้สึกว่าคำถามนี้จริงใจฉันต้องการทราบความแตกต่างอื่น ๆ มิฉะนั้นจะทิ้งความคิดเห็นของฉัน
Abid Rahman K

1
@AbidRahmanK ของหลักสูตรแนวคิดเดียวกัน, งานเหมือนกัน กำลังใช้การกรองแบบมัธยฐานบางครั้งกำลังใช้อยู่ฉันไม่สนใจว่าจะใช้ความคิดแบบไหน - มันไม่ได้ใช้ที่นี่เลย การวัดองค์ประกอบแตกต่างกัน "การพังทลายของการขยายตัวบางอย่าง" ไม่ได้ให้ขอบไบนารีใช้ otsu สำหรับสิ่งนั้น มันไม่มีจุดหมายที่จะพูดถึงเรื่องนี้รหัสอยู่ที่นั่น
mmgp

1
เคขอบคุณ ได้คำตอบ Concept is the same. (ฉันไม่เคยใช้ Mathematica ดังนั้นฉันจึงไม่สามารถเข้าใจโค้ดได้) และความแตกต่างที่คุณพูดถึงคือความแตกต่าง แต่ไม่ใช่วิธีการหรือหลักที่แตกต่างกัน หากคุณยังทำเช่นนั้นให้ตรวจสอบสิ่งนี้:
Abid Rahman K

14

ฉันสาย


ในภาพของคุณกระดาษเป็นในขณะที่พื้นหลังเป็นwhite coloredดังนั้นมันจะดีกว่าที่จะตรวจสอบกระดาษเป็นช่องทางในการSaturation(饱和度) HSV color spaceดูที่ wiki HSL_and_HSVก่อน แล้วฉันจะคัดลอกความคิดที่มากที่สุดจากคำตอบของฉันในการตรวจจับสีส่วนงานในภาพ


ขั้นตอนหลัก:

  1. อ่านเข้าไป BGR
  2. แปลงภาพจากbgrเป็นhsvพื้นที่
  3. กำหนดช่องสัญญาณ S
  4. จากนั้นหารูปร่างภายนอกสูงสุด (หรือทำCannyหรือHoughLinesตามที่คุณต้องการฉันเลือกfindContours) ประมาณเพื่อให้ได้มุม

นี่คือผลลัพธ์ของฉัน:

ป้อนคำอธิบายรูปภาพที่นี่


รหัส Python (Python 3.5 + OpenCV 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. จะใช้ `cv2.findContours` ใน OpenCV เวอร์ชั่นต่าง ๆ ได้อย่างไร?

ฉันพยายามใช้ S space แต่ก็ยังไม่ประสบความสำเร็จ ดูสิ่งนี้: stackoverflow.com/questions/50699893/…
hchouhan02

3

สิ่งที่คุณต้องการคือรูปสี่เหลี่ยมแทนที่จะเป็นรูปสี่เหลี่ยมผืนผ้าที่หมุน RotatedRectจะให้ผลลัพธ์ที่ไม่ถูกต้อง นอกจากนี้คุณจะต้องประมาณการมุมมอง

โดยพื้นฐานสิ่งที่ต้องทำคือ:

  • วนซ้ำทุกส่วนของรูปหลายเหลี่ยมและเชื่อมต่อส่วนที่เกือบเท่ากับ
  • จัดเรียงเพื่อให้คุณมีกลุ่มบรรทัดที่ใหญ่ที่สุด 4 กลุ่ม
  • ตัดเส้นเหล่านั้นและคุณมี 4 จุดที่เป็นไปได้มากที่สุด
  • แปลงเมทริกซ์ให้อยู่เหนือมุมมองที่รวบรวมจากจุดมุมและอัตราส่วนกว้างยาวของวัตถุที่รู้จัก

ฉันใช้ห้องเรียน Quadrangleที่ดูแลรูปร่างเพื่อการแปลงควอดสี่เหลี่ยมและจะเปลี่ยนผ่านมุมมองที่ถูกต้อง

ดูการใช้งานที่ใช้งานได้ที่นี่: Java OpenCV ให้ความสำคัญกับรูปร่าง


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

การตรวจจับแผ่นกระดาษเป็นโรงเรียนเก่า หากคุณต้องการจัดการกับการตรวจจับการเอียงดังนั้นจะเป็นการดีกว่าถ้าคุณตั้งเป้าหมายการตรวจจับบรรทัดข้อความ ด้วยวิธีนี้คุณจะได้รับ extremas ซ้ายขวาบนและล่าง ทิ้งกราฟิกใด ๆ ในภาพถ้าคุณไม่ต้องการแล้วทำสถิติบางอย่างในส่วนของบรรทัดข้อความเพื่อค้นหาช่วงมุมที่เกิดขึ้นมากที่สุดหรือมุมที่ค่อนข้าง นี่คือวิธีที่คุณจะแคบลงเป็นมุมเอียงที่ดี หลังจากนี้คุณวางพารามิเตอร์เหล่านี้เป็นมุมเอียงและส่วนขยายเพื่อขยายและสับรูปภาพตามที่ต้องการ

สำหรับข้อกำหนดของรูปภาพปัจจุบันจะดีกว่าถ้าคุณลอง CV_RETR_EXTERNAL แทน CV_RETR_LIST

อีกวิธีหนึ่งในการตรวจหาขอบคือการฝึกตัวจําแนกแบบฟอเรสต์แบบสุ่มบนขอบกระดาษแล้วใช้ตัวจําแนกเพื่อรับแผนที่ขอบ นี่เป็นวิธีที่แข็งแกร่ง แต่ต้องใช้เวลาและการฝึกฝน

ป่าสุ่มจะทำงานกับสถานการณ์ที่แตกต่างของความคมชัดต่ำเช่นกระดาษสีขาวบนพื้นหลังสีขาวคร่าวๆ

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.