2017-05-14 101 views
0

我已經成功檢測到包圍盒,現在我想刪除圖像中的所有其他內容,只是保留邊界框的內容以提高tesseract準確性,下面是圖像表示形式所做的和需要(我想要的二進制圖像只包含字母,要刪除所有其他對象):OpenCV Java從場景中刪除對象

I want the binary images to only contain the letters, all the other objects to be removed

和我的代碼:

public static ProcessedFrame preProcessImage(Mat image){ 
    originalFrame = image.clone(); 
    roiColor = image.clone(); 
    Imgproc.cvtColor(image, image, Imgproc.COLOR_BGR2GRAY, 0); 
    originalFrameGrayScale = image.clone(); 
    Mat morph = Imgproc.getStructuringElement(Imgproc.MORPH_RECT, new Size(9, 9)); 
    Imgproc.morphologyEx(image, image, Imgproc.MORPH_TOPHAT, morph); 
    Imgproc.Sobel(image, image, -1, 2, 0); 
    Imgproc.GaussianBlur(image, image, new Size(5,5), 3,3); 
    Imgproc.morphologyEx(image, image, Imgproc.MORPH_CLOSE, morph); 
    Imgproc.threshold(image, image, 200, 255, Imgproc.THRESH_OTSU); 
    Vector<Rect> rectangles = detectionContour(image); 
    Mat roi = originalFrameGrayScale.clone(); 
    if(!rectangles.isEmpty()){ 
    roi = originalFrameGrayScale.submat(rectangles.get(0)); 
    roiBlack = roi.clone(); 
    roiColor = roiColor.submat(rectangles.get(0)); 
     Imgproc.rectangle(originalFrame, rectangles.get(0).br(), rectangles.get(0).tl(), new Scalar(0,0,255), 2); 
    } 
    Imgproc.medianBlur(roi, roi, 3); 
    Imgproc.adaptiveThreshold(roi, roi, 225, Imgproc.ADAPTIVE_THRESH_GAUSSIAN_C, Imgproc.THRESH_BINARY, 15, 3); 
    Imgproc.medianBlur(roi, roi, 3); 
    Imgproc.medianBlur(roi, roi, 3); 
    Imgproc.adaptiveThreshold(roi, roi, 225, Imgproc.ADAPTIVE_THRESH_GAUSSIAN_C, Imgproc.THRESH_BINARY, 15, 3); 
    Imgproc.medianBlur(roi, roi, 3); 
    roiBinarize = roi.clone(); 
    Mat erode = Imgproc.getStructuringElement(Imgproc.MORPH_RECT, new Size(3, 3)); 
    Mat dilate = Imgproc.getStructuringElement(Imgproc.MORPH_RECT,new Size(3, 3)); 
    Imgproc.morphologyEx(roi, roi, Imgproc.MORPH_CLOSE, dilate); 
    Imgproc.morphologyEx(roi, roi, Imgproc.MORPH_CLOSE, erode); 
    Vector<Rect> letters = detectionPlateCharacterContour(roi); 
    doTesseractOCR(letters, roiBinarize); 
    return new ProcessedFrame(originalFrame, roiColor, roiBinarize, roi); 

} 






private static void doTesseractOCR(Vector<Rect> letters, Mat plate){ 
    Tesseract instance = new Tesseract(); // 
    instance.setLanguage(LANGUAGE); 
    String resultPlate = "AAA0000"; 
    for(int i= 0; i < letters.size(); i++){ 

    BufferedImage letter = OpenCvUtils.Mat2bufferedImage(plate.submat(letters.get(i))); 
     try { 
     String result = instance.doOCR(letter); 
     String character = result.replace("\n", ""); 
     resultPlate = new StringBuilder(resultPlate).replace(i ,i+1, character).toString(); 
     } catch (TesseractException e) { 
     System.err.println(e.getMessage()); 
     } 

     System.out.println("Tesseract output: "+resultPlate); 
    } 

    try { 
     String result = instance.doOCR(OpenCvUtils.Mat2bufferedImage(roiBinarize)); 
     System.out.println("Tesseract output2: "+result.replace("\n", "")); 
     } catch (TesseractException e) { 
     System.err.println(e.getMessage()); 
     } 
} 





private static Vector<Rect> detectionPlateCharacterContour(Mat roi) { 
    Mat contHierarchy = new Mat(); 
    Mat imageMat = roi.clone(); 
    Rect rect = null; 
    List<MatOfPoint> contours = new ArrayList<>(); 
    Imgproc.findContours(imageMat, contours, contHierarchy, Imgproc.RETR_CCOMP, Imgproc.CHAIN_APPROX_SIMPLE); 
    Vector<Rect> rect_array = new Vector<>(); 

    for (int i = 0; i < contours.size(); i++) { 
     rect = Imgproc.boundingRect(contours.get(i)); 
     double ratio = 0; 

       if(rect.height > rect.width){ 
      ratio = rect.height/rect.width; 

      }else{ 
       ratio = rect.width/rect.height; 

      } 
     Logger.printMessage("Ratio of letter: "+ratio); 
     double contourarea = Imgproc.contourArea(contours.get(i)); 
     if (contourarea >= 160 && contourarea <= 1000 && (ratio >= 1 && ratio <= 2)) { 
     Imgproc.rectangle(roiColor, rect.br(), rect.tl(), new Scalar(10,50,255)); 
      rect_array.add(rect); 
     } 
    } 


    contHierarchy.release(); 
    return rect_array; 
} 




private static Vector<Rect> detectionContour(Mat outmat) { 
    Mat contHierarchy = new Mat(); 
    Mat imageMat = outmat.clone(); 

    List<MatOfPoint> contours = new ArrayList<>(); 

    Imgproc.findContours(imageMat, contours, contHierarchy, Imgproc.RETR_EXTERNAL, Imgproc.CHAIN_APPROX_NONE); 

    Vector<Rect> rect_array = new Vector<>(); 
    for (int i = 0; i < contours.size(); i++) { 
     Rect rect = Imgproc.boundingRect(contours.get(i)); 

     Mat contour = contours.get(i); 
     double contourarea = Imgproc.contourArea(contour); 

      double ratio = 0; 
      int radius = 0; 
      if(rect.height > rect.width){ 
      ratio = rect.height/rect.width; 
      radius = rect.height/2; 
      }else{ 
       ratio = rect.width/rect.height; 
       radius = rect.width/2; 
      } 
     if (contourarea >= 2000 && contourarea <= 10000 && (ratio == 1 || ratio == 2)) { 
      Logger.printMessage("Rectangle ratio: "+ratio); 
      MatOfPoint2f mat2f = new MatOfPoint2f(); 
      contours.get(i).convertTo(mat2f, CvType.CV_32FC2); 
      RotatedRect rotatedRect = Imgproc.minAreaRect(mat2f); 
      double rotationAngle = rotatedRect.angle; 
      if(rotatedRect.angle > 0) 
       rotationAngle = 90 - rotatedRect.angle; 
      else 
       rotationAngle = rotatedRect.angle; 
      Logger.printMessage("Rotation is: "+(rotationAngle)); 
      rect = enlargeROI(originalFrame, rect, 10); 
      rect_array.add(rect); 
     } 
    } 


    contHierarchy.release(); 
    return rect_array; 
} 





private Vector<Rect> detectionContours(Mat outmat) { 
    Mat contHierarchy = new Mat(); 
    Mat imageMat = outmat.clone(); 
    Rect contourRect = null; 
    List<MatOfPoint> contours = new ArrayList<>(); 
    Imgproc.findContours(imageMat, contours, contHierarchy, Imgproc.RETR_LIST, Imgproc.CHAIN_APPROX_SIMPLE); 
    Vector<Rect> rect_array = new Vector<>(); 
    for (int i = 0; i < contours.size(); i++) { 
     Mat contour = contours.get(i); 
     double contourarea = Imgproc.contourArea(contour); 
     if (contourarea > minBlob && contourarea < maxBlob) { 
      contourRect = Imgproc.boundingRect(contours.get(i)); 
      rect_array.add(contourRect); 
     } 
    } 


    contHierarchy.release(); 
    return rect_array; 
} 

當我運行這段代碼打印出來每一個矩形的形心我發現 2×:18.0 Y:111.0 2×:42.0 Y:109.0 7×:65.0 Y:108.0 0X:89.0 Y:108.0 甲X:29.0 Y:61.0 ÇX: 52.0 y:58.0 x:77.0 y:58.0

+0

的[OpenCV的增強圖像OCR]可能的複製(http://stackoverflow.com/questions/43958962/opencv-enhancing-image-for-ocr) - 請不要發佈關於顯然是同一問題的另一個問題,而是適當地增強原始問題。 –

+0

我刪除了帖子,它被錯誤地詢問。 –

+0

OK :) |你想替換「刪除」圖像的哪些部分? (我假設我們正在討論關於附加圖像右下角的圖像的一些進一步的步驟。)由於您提供了一個邊界框向量,用於指定個別檢測到的字母,我認爲這只是一些外觀要求用於顯示? –

回答

0

看來你只需要對你的字母邊界框做一些預處理,在將它們送到Tesseract之前做它可能是有意義的,儘管它不是嚴格的必要。我們首先用輪廓索引註釋我們的樣本圖像,並列出它們的屬性。

Annotated LP

contour | bbox centroid | recognised 
index | x | y | symbol 
--------+-------+-------+----------- 
0  | 18.0 | 111.0 | 2 
1  | 42.0 | 109.0 | 2 
2  | 65.0 | 108.0 | 7 
3  | 89.0 | 108.0 | 0 
4  | 29.0 | 61.0 | A 
5  | 52.0 | 58.0 | C 
6  | 77.0 | 58.0 | P 

當一個人讀這個車牌,便開始與符號的最頂層的行,並讀取符號由左到右。在他們到達最右邊的符號後,他們移動到下一行,再次從左到右。因此,我們應該將我們的符號(或代表它們的邊界框)組織在一個能讓我們輕鬆完成的結構中。

我們可以用Vector<Rect>來表示每一行符號。由於總是有兩行符號,所以我們需要這個向量的兩個實例 - 讓我們將它們稱爲row0row1


第一個任務是將符號的邊界框分爲兩組,並基於此將它們添加到適當的行向量中。一個簡單的方法可能是這樣的:

  • 計算符號質心座標y的平均值。在我們的例子中,它大約是mean_y=87.5
  • 對於每個檢測到的符號:
    • 如果y符號質心的座標小於mean_y,符號添加到ROW0
    • 否則符號添加到ROW1

當我們對我們的樣本符號集執行此算法時,我們看到

 | contained 
row | symbol ids 
-----+-------------- 
row0 | 4, 5, 6 
row1 | 0, 1, 2, 3 

如果這種簡單的方法變得不足,您可以嘗試一些更高級的means of clustering


第二個任務是使符號向左走向右各行進行排序:

  • 對於每一行:
    • 按升序排序行元素由x的協調centroid

我的Java很生疏,但你可以使用comparator來做到這一點。您可以參考this SO answer瞭解更多關於如何在Java中對集合進行排序的細節。

在我們的樣本中,每一行中的元素已經有序,所以沒有什麼做的......

 | contained 
row | symbol ids 
-----+-------------- 
row0 | 4, 5, 6 
row1 | 0, 1, 2, 3 

現在我們可以

  • 對於每一行:
    • 對於行中的每個符號
      • 用Tesseract處理
      • 根據需要處理結果(例如,打印)

在我們的樣本中,我們會得到

ACP 
2270