2014-10-09 21 views
6

Şu anki plaka görüntülerini bölümlere ayırırken sorunla karşılaşıyorum; aşağıdaki resimler eşiklenirken karakterler 1 karakterden fazla kırılır. Bu yüzden hatalı bir şekilde OCR sonucu alıyorum. Ben .. Hatta ondan sonra düzgün karakterler segmentine mümkün değilim, görüntü eşikleme sonraResimden karakterleri segmentlere ayırma

License Plate image 1

License Plate image 2

License Plate image 3

License Plate image 4

morfolojik kapanış işlemi uyguladık Yukarıdaki bölümlere ayırmak için kullanılan kod aşağıda

verilmiştir.

aşağıda verilen çıkış görüntüleri

#include <iostream> 
#include<cv.h> 
#include<highgui.h> 

using namespace std; 
using namespace cv; 
int main(int argc, char *argv[]) 
{ 
    IplImage *img1 = cvLoadImage(argv[1] , 0); 
    IplImage *img2 = cvCloneImage(img1); 

    cvNamedWindow("Orig"); 
    cvShowImage("Orig",img1); 
    cvWaitKey(0); 

    int wind = img1->height; 
    if (wind % 2 == 0) wind += 1; 

    cvAdaptiveThreshold(img1, img1, 255, CV_ADAPTIVE_THRESH_GAUSSIAN_C, 
         CV_THRESH_BINARY_INV, wind); 

    IplImage* temp = cvCloneImage(img1); 

    cvNamedWindow("Thre"); 
    cvShowImage("Thre",img1); 
    cvWaitKey(0); 

    IplConvKernel* kernal = cvCreateStructuringElementEx(3, 3, 1, 1, 
                 CV_SHAPE_RECT,NULL); 

    cvMorphologyEx(img1, img1, temp, kernal, CV_MOP_CLOSE, 1); 

    cvNamedWindow("close"); 
    cvShowImage("close",img1); 

    cvWaitKey(0); 
} 
..

U Y and 2 are not segmented properly

U, P, Y and 2 are not segmented Properly

U 3 Y 2 and 5 are not segmented properly

herkes bu görüntülerden segmenti karakterleri için iyi bir yöntem sağlayabilir

... ??

+0

Yardımcı olur emin değilim - http://stackoverflow.com/a/10970473/2380071 Ya da bu - http://stackoverflow.com/a/14372743/2380071 – LKB

+0

dilatasyon ve erozyon çalışmıyor Benim için .. – Deepak

cevap

12

Ben karakterlerin gerçek segmentasyon sorun değildir çünkü plakalarda harfleri/sayıları izole etmek hızlı & kirli bir yaklaşım göstermek istiyorum. Bu giriş görüntüleri olduğunda:

enter image description hereenter image description here enter image description hereenter image description here

yüzden tartışmak Ne:

enter image description hereenter image description here enter image description hereenter image description here

Bu benim algoritmanın sonunda elde ediyoruz Bu cevap size bazı fikirler verecektir ve c'nizin sonunda bulunan eserlerinizden kurtulmanıza yardımcı olacaktır. eş zamanlı segmentasyon süreci. Bu yaklaşımın yalnızca bu tür resimlerle çalışması gerektiğini ve daha sağlam bir şeye ihtiyacınız varsa, bazı şeyleri ayarlamanız veya bu şeyleri yapmak için tamamen yeni yollar bulmanız gerektiğini unutmayın.

enter image description hereenter image description here : köklü değişiklikler parlaklık Verilen

  • , bu kontrastı artırmak ve böylece diğer tüm teknikler ve parametreler onlarla çalışmak birbirine onları daha benzer hale getirmek için histogram equalization yürütmek için en iyisi enter image description hereenter image description here

    • Daha sonra, bir bilateral filter ed korunurken görüntü düzeltmek için kullanılabilir binarizasyon süreci için önemli olan nesnelerin ges'i. Bu filtre biraz daha fazla işleme gücü than others.

    enter image description hereenter image description here enter image description hereenter image description here

    :

enter image description hereenter image description here enter image description hereenter image description here

    görüntüleri ikileştirildikten hazırdır sonra o
  • , bir hile yapmak için kullanılır

enter image description hereenter image description here enter image description hereenter image description here

    :
      çiftlemeye sonucu başardığın ne benzer olduğunu
    • , bu yüzden daha küçük ve daha büyük segmentleri kaldırmak için findContours() kullanmanın bir yolu ile geldi
    • Sonuç biraz daha iyi görünüyor, ancak plakadaki karakterlerin önemli bölümlerini yok etti. Ancak, şu anda bu gerçekten bir sorun değil çünkü karakteri tanımak konusunda endişelenmiyoruz: sadece bulunduğu alanı ayırmak istiyoruz. Bir sonraki adım, segmentleri, özellikle de rakamların aynı Y ekseni ile hizalanmamış olanları silmeye devam etmektir. Bu kesim işlemini hayatta konturlar şunlardır:

    enter image description hereenter image description here enter image description hereenter image description here

    • Bu çok daha iyi olduğunu ve bu noktada yeni std::vector<cv::Point> tüm çizmek için gerekli koordinatları tüm piksel depolamak için oluşturulan bu segmentler. Bu bize oluşturmanıza olanak veren budur bir cv::RotatedRect oluşturmak için gerekli olan bounding box ve ayrıca crop the image: Bu noktadan itibaren

    enter image description hereenter image description here enter image description hereenter image description here

    ileri kendi teknikleri yürütmek için kırpılmış resimleri kullanabilirsiniz ve kolayca plaka karakterlerini segmentlere ayırın.

    İşte C++ kod geçerli: OpenCV ile plaka tanıma yapmanın daha eksiksiz ve sağlam bir şekilde İçin

    #include <iostream> 
    #include <vector>  
    #include <opencv2/highgui/highgui.hpp> 
    #include <opencv2/imgproc/imgproc.hpp> 
    #include <opencv2/imgproc/imgproc_c.h> 
    
    /* The code has an outter loop where every iteration processes one of the four input images */ 
    
    std::string files[] = { "plate1.jpg", "plate2.jpg", "plate3.jpg", "plate4.jpg" }; 
    cv::Mat imgs[4]; 
    for (int a = 0; a < 4; a++) 
    { 
        /* Load input image */ 
    
        imgs[a] = cv::imread(files[a]); 
        if (imgs[a].empty()) 
        { 
         std::cout << "!!! Failed to open image: " << imgs[a] << std::endl; 
         return -1; 
        } 
    
        /* Convert to grayscale */ 
    
        cv::Mat gray; 
        cv::cvtColor(imgs[a], gray, cv::COLOR_BGR2GRAY); 
    
        /* Histogram equalization improves the contrast between dark/bright areas */ 
    
        cv::Mat equalized; 
        cv::equalizeHist(gray, equalized); 
        cv::imwrite(std::string("eq_" + std::to_string(a) + ".jpg"), equalized); 
        cv::imshow("Hist. Eq.", equalized); 
    
        /* Bilateral filter helps to improve the segmentation process */ 
    
        cv::Mat blur; 
        cv::bilateralFilter(equalized, blur, 9, 75, 75); 
        cv::imwrite(std::string("filter_" + std::to_string(a) + ".jpg"), blur); 
        cv::imshow("Filter", blur); 
    
        /* Threshold to binarize the image */ 
    
        cv::Mat thres; 
        cv::adaptiveThreshold(blur, thres, 255, cv::ADAPTIVE_THRESH_GAUSSIAN_C, cv::THRESH_BINARY, 15, 2); //15, 2 
        cv::imwrite(std::string("thres_" + std::to_string(a) + ".jpg"), thres); 
        cv::imshow("Threshold", thres); 
    
        /* Remove small segments and the extremelly large ones as well */ 
    
        std::vector<std::vector<cv::Point> > contours; 
        cv::findContours(thres, contours, cv::RETR_LIST, cv::CHAIN_APPROX_SIMPLE); 
    
        double min_area = 50; 
        double max_area = 2000; 
        std::vector<std::vector<cv::Point> > good_contours; 
        for (size_t i = 0; i < contours.size(); i++) 
        { 
         double area = cv::contourArea(contours[i]); 
         if (area > min_area && area < max_area) 
          good_contours.push_back(contours[i]); 
        } 
    
        cv::Mat segments(gray.size(), CV_8U, cv::Scalar(255)); 
        cv::drawContours(segments, good_contours, -1, cv::Scalar(0), cv::FILLED, 4); 
        cv::imwrite(std::string("segments_" + std::to_string(a) + ".jpg"), segments); 
        cv::imshow("Segments", segments); 
    
        /* Examine the segments that survived the previous lame filtering process 
        * to figure out the top and bottom heights of the largest segments. 
        * This info will be used to remove segments that are not aligned with 
        * the letters/numbers of the plate. 
        * This technique is super flawed for other types of input images. 
        */ 
    
        // Figure out the average of the top/bottom heights of the largest segments 
        int min_average_y = 0, max_average_y = 0, count = 0; 
        for (size_t i = 0; i < good_contours.size(); i++) 
        { 
         std::vector<cv::Point> c = good_contours[i]; 
         double area = cv::contourArea(c); 
         if (area > 200) 
         { 
          int min_y = segments.rows, max_y = 0; 
          for (size_t j = 0; j < c.size(); j++) 
          { 
           if (c[j].y < min_y) 
            min_y = c[j].y; 
    
           if (c[j].y > max_y) 
            max_y = c[j].y; 
          } 
          min_average_y += min_y; 
          max_average_y += max_y; 
          count++; 
         } 
        } 
        min_average_y /= count; 
        max_average_y /= count; 
        //std::cout << "Average min: " << min_average_y << " max: " << max_average_y << std::endl; 
    
        // Create a new vector of contours with just the ones that fall within the min/max Y 
        std::vector<std::vector<cv::Point> > final_contours; 
        for (size_t i = 0; i < good_contours.size(); i++) 
        { 
         std::vector<cv::Point> c = good_contours[i]; 
         int min_y = segments.rows, max_y = 0; 
         for (size_t j = 0; j < c.size(); j++) 
         { 
          if (c[j].y < min_y) 
           min_y = c[j].y; 
    
          if (c[j].y > max_y) 
           max_y = c[j].y; 
         } 
    
         // 5 is to add a little tolerance from the average Y coordinate 
         if (min_y >= (min_average_y-5) && (max_y <= max_average_y+5)) 
          final_contours.push_back(c); 
        } 
    
        cv::Mat final(gray.size(), CV_8U, cv::Scalar(255)); 
        cv::drawContours(final, final_contours, -1, cv::Scalar(0), cv::FILLED, 4); 
        cv::imwrite(std::string("final_" + std::to_string(a) + ".jpg"), final); 
        cv::imshow("Final", final); 
    
    
        // Create a single vector with all the points that make the segments 
        std::vector<cv::Point> points; 
        for (size_t x = 0; x < final_contours.size(); x++) 
        { 
         std::vector<cv::Point> c = final_contours[x]; 
         for (size_t y = 0; y < c.size(); y++) 
          points.push_back(c[y]); 
        } 
    
        // Compute a single bounding box for the points 
        cv::RotatedRect box = cv::minAreaRect(cv::Mat(points)); 
        cv::Rect roi; 
        roi.x = box.center.x - (box.size.width/2); 
        roi.y = box.center.y - (box.size.height/2); 
        roi.width = box.size.width; 
        roi.height = box.size.height; 
    
        // Draw the box at on equalized image 
        cv::Point2f vertices[4]; 
        box.points(vertices); 
        for(int i = 0; i < 4; ++i) 
         cv::line(imgs[a], vertices[i], vertices[(i + 1) % 4], cv::Scalar(255, 0, 0), 1, CV_AA); 
        cv::imwrite(std::string("box_" + std::to_string(a) + ".jpg"), imgs[a]); 
        cv::imshow("Box", imgs[a]); 
    
        // Crop the equalized image with the area defined by the ROI 
        cv::Mat crop = equalized(roi); 
        cv::imwrite(std::string("crop_" + std::to_string(a) + ".jpg"), crop); 
        cv::imshow("crop", crop); 
    
        /* The cropped image should contain only the plate's letters and numbers. 
        * From here on you can use your own techniques to segment the characters properly. 
        */ 
    
        cv::waitKey(0); 
    } 
    

    , Mastering OpenCV with Practical Computer Vision Projects bakmak bölüm 5. Source code is available on Github!

+0

Son görüntüden segmentleri nasıl segmentlere ayırabiliriz? (Doldurma ve morfolojik kapanma işlemi mükemmel çalışmaz, çünkü plakaların çoğunda karakterler birbirine çok yakındır) – Deepak

+0

Sağladığınız son görüntüde Y, 5, 2 karakterleri kesildi.Yani cvFindContour() kullanarak bunları farklı segmentler olarak elde ederiz. Bu, yanlış OCR çıktısı ile sonuçlanır. – Deepak

+0

[Yapabilirsiniz] (https://github.com/aperrau/detecttext) [takip et] (http://stackoverflow.com/a/12785869/176769) [çok farklı] (http://stackoverflow.com/q/23104244/176769) [yaklaşımlar] (http://docs.opencv.org/trunk/modules/text/doc/text.html) [bunun için] (http://stackoverflow.com/q/23361583/176769) Yukarıda belirtilen bölüm dahil. – karlphillip