2014-10-27 26 views
5

http://oi60.tinypic.com/51lkp.jpgOpenCV C++ - rilevamento rettangolare che ha lato irregolare

Hi .. Ho problemi con il rilevamento rettangolo che ha lato irregolare (non diritto) come figura sopra. in realtà con method houghline è possibile rilevare linee sul rettangolo con qualche configurazione di parametri. Dopo aver calcolato l'intersezione e ottenuto 4 angoli, posso ruotarlo in posizione normale.

Ma se cambio l'immagine con un altro rettangolo (di dimensioni diverse e ha ancora il lato irregolare), ho bisogno di riconfigurare nuovamente i parametri. Questo perché la linea non viene rilevata su quattro lati, oltre alla linea può essere più di 4.

c'è qualche altro metodo accanto a houghline che è più semplice (non richiede riconfigurazione/configurazione difficile)?

+0

forse si può considerare di dilatazione e di erosione sequenze a Crea un rettangolo più 'regolare' allo scopo di ottenere le coordinate dell'angolo con il metodo del contorno. puoi quindi ruotare il rettangolo originale dopo. –

+0

L'esempio di squares.cpp negli esempi OpenCV potrebbe aiutarti. Utilizzare una soglia semplice, estrarre contorni esterni, quindi eseguire un'approssimazione poligonale di questi contorni come mostrato nel campione. – dhanushka

+0

Prova questo: http://docs.opencv.org/modules/imgproc/doc/structural_analysis_and_shape_descriptors.html?highlight=minarearect#minarearect – Micka

risposta

5

In questo modo è possibile calcolare il rettangolo ruotato che contiene tutti i pixel del rettangolo.

Forse è possibile combinare che, con la risposta di Vasanth, in modo da poter prima approssimare il polinomio per ottenere un bordo regolare e poi estrarre il rettangolo ruotato con cv::minAreaRect

Ecco il mio codice:

int main() 
{ 
    cv::Mat input = cv::imread("../inputData/RotatedRect.png"); 

    // convert to grayscale (you could load as grayscale instead) 
    cv::Mat gray; 
    cv::cvtColor(input,gray, CV_BGR2GRAY); 

    // compute mask (you could use a simple threshold if the image is always as good as the one you provided) 
    cv::Mat mask; 
    cv::threshold(gray, mask, 0, 255, CV_THRESH_BINARY_INV | CV_THRESH_OTSU); 

    // find contours (if always so easy to segment as your image, you could just add the black/rect pixels to a vector) 
    std::vector<std::vector<cv::Point>> contours; 
    std::vector<cv::Vec4i> hierarchy; 
    cv::findContours(mask,contours, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE); 

    /// Draw contours and find biggest contour (if there are other contours in the image, we assume the biggest one is the desired rect) 
    // drawing here is only for demonstration! 
    int biggestContourIdx = -1; 
    float biggestContourArea = 0; 
    cv::Mat drawing = cv::Mat::zeros(mask.size(), CV_8UC3); 
    for(int i = 0; i< contours.size(); i++) 
    { 
     cv::Scalar color = cv::Scalar(0, 100, 0); 
     drawContours(drawing, contours, i, color, 1, 8, hierarchy, 0, cv::Point()); 

     float ctArea= cv::contourArea(contours[i]); 
     if(ctArea > biggestContourArea) 
     { 
      biggestContourArea = ctArea; 
      biggestContourIdx = i; 
     } 
    } 

    // if no contour found 
    if(biggestContourIdx < 0) 
    { 
     std::cout << "no contour found" << std::endl; 
     return 1; 
    } 

    // compute the rotated bounding rect of the biggest contour! (this is the part that does what you want/need) 
    cv::RotatedRect boundingBox = cv::minAreaRect(contours[biggestContourIdx]); 
    // one thing to remark: this will compute the OUTER boundary box, so maybe you have to erode/dilate if you want something between the ragged lines 



    // draw the rotated rect 
    cv::Point2f corners[4]; 
    boundingBox.points(corners); 
    cv::line(drawing, corners[0], corners[1], cv::Scalar(255,255,255)); 
    cv::line(drawing, corners[1], corners[2], cv::Scalar(255,255,255)); 
    cv::line(drawing, corners[2], corners[3], cv::Scalar(255,255,255)); 
    cv::line(drawing, corners[3], corners[0], cv::Scalar(255,255,255)); 

    // display 
    cv::imshow("input", input); 
    cv::imshow("drawing", drawing); 
    cv::waitKey(0); 

    cv::imwrite("rotatedRect.png",drawing); 

    return 0; 
} 

dare questo risultato:

enter image description here

+1

grazie Micka .. questo metodo funziona per me .. grazie anche per la spiegazione in quel codice – stranger

4

Utilizzando geometria elementare, è necessario trovare il co-ordinata dove

  • posizione del pixel nero con piccoli coordinata x
  • posizione pixel nero con la più grande coordinata x
  • nero pixel posizione con più piccolo coordinata y
  • posizione pixel nero con la più grande co-ordinata y

Questi 4 punti saranno i bordi del tuo rettangolo.

+0

Grazie bikz05, apprezzo la tua risposta, +1 alla semplicità – stranger

3

Prova questa:

1.Run findCountours sull'immagine.

2.Applicare approxPolyDP per approssimare il contorno a un rettangolo. I lati del contorno saranno molto più regolari.

3.Segmentare i contorni rettangolari utilizzando moments e/o la geometria.

+0

Grazie Vasanth, apprezzo la tua risposta, ora conosco altro metodo accanto a houghline – stranger