2016-12-14 9 views
4

私は徹底的な研究を行っており、私が必要とするものを達成するための技術の組み合わせを見つけることはできません。opencv - pythonを使ってW2の個々のボックスを検出する

私は、調整のためにデータを抽出するために何百ものW2でOCRを実行する必要がある状況があります。 W2は、印刷された後にスキャンされてコンピュータに戻されるため、品質が非常に悪いものです。上記のプロセスは私のコントロール外です。残念ながら、私は私が持っているもので動作する必要があります。

私は昨年、このプロセスを正常に実行できましたが、適時性が大きな懸念事項であったため、強制的に強制しなければなりませんでした。データを抽出するための座標を手動で指定してから、一度に1つのセグメントに対してのみOCRを実行することで、そのようにしました。今年は、座標が変わる可能性があり、フォーマットが変わる可能性があると予想して、よりダイナミックな状況を作り出したいと思います。

私は以下のサンプルを取り除きました。考え方は、W2の各ボックスがそれ自身の矩形であり、すべての矩形を反復してデータを抽出することです。私はいくつかのエッジ検出手法を試しましたが、必要なものを正確には提供していません。私は、必要な前処理の正しい組み合わせが見つからないと考えています。数独パズル検出スクリプトの一部をミラーリングしようとしました。

Processed W2

import cv2 
import numpy as np 

img = cv2.imread(image_path_here) 

newx,newy = img.shape[1]/2,img.shape[0]/2 
img = cv2.resize(img,(newx,newy)) 
blur = cv2.GaussianBlur(img, (3,3),5) 
ret,thresh1 = cv2.threshold(blur,225,255,cv2.THRESH_BINARY) 

gray = cv2.cvtColor(thresh1,cv2.COLOR_BGR2GRAY) 

edges = cv2.Canny(gray,50,220,apertureSize = 3) 

minLineLength = 20 
maxLineGap = 50 
lines = cv2.HoughLinesP(edges,1,np.pi/180,100,minLineLength,maxLineGap) 

for x1,y1,x2,y2 in lines[0]: 
    cv2.line(img,(x1,y1),(x2,y2),(255,0,255),2) 

cv2.imshow('hough',img) 
cv2.waitKey(0) 
+0

問題はこれとこれは垂直線はほとんど検出されないパラメータことで、 '' lines_v = cv2.HoughLinesP(エッジ、1、np.pi、100、minLineLength、maxLineGap)と垂直線を見つけることを試みますこれのために別のループを作ってください。 'HoughLinesP'関数のための異なるパラメータ値を試してください。水平線と垂直線に対して異なる値を設定してください。 – ebeneditos

答えて

2

を:ここ

Example W2

私はOpenCVの2または3とするかどうかを使用することができるPythonコードと共に、これまでに試みたものの結果でありますあなたが私のコードの中で何かを従わないと私に教えてください。この概念の最大の障害は、

1以下のとおりです。(あなたは別の塊にそれを壊すメインボックスラインで騒々しいブレークを持っている場合)

2:これは手書きのテキストが存在することができるものであればIDKのしかし、文字を持つとボックスの端が重なってしまうことがあります。

3:姿勢チェックは絶対にありません(実際にはこれを改善したいと思うかもしれませんが、それはあまりにも悪くなく、より正確なハンドルを与えるでしょう)。私は、あなたのボックスがxy軸にほぼ揃っているかどうか、それらが十分に歪んでいる場合、すべてのボックスコーナーにグロスオフセットを与えます(ただしそれらはまだすべて見つける必要があります)。

I fiddledすべてのテキストがエッジから分離されるようにしきい値設定ポイントを少し設定すると、必要に応じてメインラインを破る前にそれをさらに下げることができます。また、改行が心配な場合は、最終的な画像に十分大きな塊を追加することもできます。 Processing steps

Final result

基本的に

、最も安定した(まだ接続箱を保つ可能性が最も低い値)でそれを得るために、閾値をいじるの最初のステップのボックスからテキストやノイズを分離するためのcuttoff値。

2番目に大きい正のBLOBを見つける(ボックスグリッドにする必要があります)。あなたのボックスがすべて一緒にいなければ、最高のブロブをいくつか取りたいかもしれませんが、それは粘着性になりますが、単一のブロブとして得ることができるように閾値を取得しようとします。

最後のステップでは、これを行うために、矩形を取得することです(最初の外側領域を無視して)負のブロブを探します。

そしてここでのコードは、(それはC++であることを申し訳ありませんが、うまくいけば、あなたが概念を理解し、とにかくそれを自分で書きます)です:

#include "opencv2/imgproc/imgproc.hpp" 
#include "opencv2/highgui/highgui.hpp" 
#include <iostream> 
#include <stdio.h> 
#include <opencv2/opencv.hpp> 

using namespace cv; 


//Attempts to find the largest connected group of points (assumed to be the interconnected boundaries of the textbox grid) 
Mat biggestComponent(Mat targetImage, int connectivity=8) 
{ 
    Mat inputImage; 
    inputImage = targetImage.clone(); 
    Mat finalImage;// = inputImage; 
    int greatestBlobSize=0; 
    std::cout<<"Top"<<std::endl; 
    std::cout<<inputImage.rows<<std::endl; 
    std::cout<<inputImage.cols<<std::endl; 

    for(int i=0;i<inputImage.cols;i++) 
    { 
     for(int ii=0;ii<inputImage.rows;ii++) 
     { 
      if(inputImage.at<uchar>(ii,i)!=0) 
      { 
       Mat lastImage; 
       lastImage = inputImage.clone(); 
       Rect* boundbox; 
       int blobSize = floodFill(inputImage, cv::Point(i,ii), Scalar(0),boundbox,Scalar(200),Scalar(255),connectivity); 

       if(greatestBlobSize<blobSize) 
       { 
        greatestBlobSize=blobSize; 
        std::cout<<blobSize<<std::endl; 
        Mat tempDif = lastImage-inputImage; 
        finalImage = tempDif.clone(); 
       } 
       //std::cout<<"Loop"<<std::endl; 
      } 
     } 
    } 
    return finalImage; 
} 

//Takes an image that only has outlines of boxes and gets handles for each textbox. 
//Returns a vector of points which represent the top left corners of the text boxes. 
std::vector<Rect> boxCorners(Mat processedImage, int connectivity=4) 
{ 
    std::vector<Rect> boxHandles; 

    Mat inputImage; 
    bool outerRegionFlag=true; 

    inputImage = processedImage.clone(); 

    std::cout<<inputImage.rows<<std::endl; 
    std::cout<<inputImage.cols<<std::endl; 

    for(int i=0;i<inputImage.cols;i++) 
    { 
     for(int ii=0;ii<inputImage.rows;ii++) 
     { 
      if(inputImage.at<uchar>(ii,i)==0) 
      { 
       Mat lastImage; 
       lastImage = inputImage.clone(); 
       Rect boundBox; 

       if(outerRegionFlag) //This is to floodfill the outer zone of the page 
       { 
        outerRegionFlag=false; 
        floodFill(inputImage, cv::Point(i,ii), Scalar(255),&boundBox,Scalar(0),Scalar(50),connectivity); 
       } 
       else 
       { 
        floodFill(inputImage, cv::Point(i,ii), Scalar(255),&boundBox,Scalar(0),Scalar(50),connectivity); 
        boxHandles.push_back(boundBox); 
       } 
      } 
     } 
    } 
    return boxHandles; 
} 

Mat drawTestBoxes(Mat originalImage, std::vector<Rect> boxes) 
{ 
    Mat outImage; 
    outImage = originalImage.clone(); 
    outImage = outImage*0; //really I am just being lazy, this should just be initialized with dimensions 

    for(int i=0;i<boxes.size();i++) 
    { 
     rectangle(outImage,boxes[i],Scalar(255)); 
    } 
    return outImage; 
} 

int main() { 

    Mat image; 
    Mat thresholded; 
    Mat processed; 

    image = imread("Images/W2.png", 1); 
    Mat channel[3]; 

    split(image, channel); 


    threshold(channel[0],thresholded,150,255,1); 

    std::cout<<"Coputing biggest object"<<std::endl; 
    processed = biggestComponent(thresholded); 

    std::vector<Rect> textBoxes = boxCorners(processed); 

    Mat finalBoxes = drawTestBoxes(image,textBoxes); 


    namedWindow("Original", WINDOW_AUTOSIZE); 
    imshow("Original", channel[0]); 

    namedWindow("Thresholded", WINDOW_AUTOSIZE); 
    imshow("Thresholded", thresholded); 

    namedWindow("Processed", WINDOW_AUTOSIZE); 
    imshow("Processed", processed); 

    namedWindow("Boxes", WINDOW_AUTOSIZE); 
    imshow("Boxes", finalBoxes); 



    std::cout<<"waiting for user input"<<std::endl; 

    waitKey(0); 

    return 0; 
} 
3

彼は、エッジ検出が唯一の方法ではありません。エッジが十分厚く(少なくとも1ピクセルはどこでも)、2値化によってボックス内の領域を単一化することができます。

単純な基準では、混乱を取り除くことができ、バウンディングボックスだけでかなり良いセグメンテーションが得られます。

enter image description here

+0

Sneaky Polar Bearのアプローチと似ています。 –

関連する問題