opencv를 사용하여 이미지에 존재하는 모든 텍스트의 위치를 ​​가져옵니다.


11

텍스트 (숫자 및 알파벳)가 들어있는이 이미지가 있습니다. 이 이미지에있는 모든 텍스트와 숫자의 위치를 ​​얻고 싶습니다. 또한 모든 텍스트를 추출하고 싶습니다.

여기에 이미지 설명을 입력하십시오

내 이미지의 모든 텍스트 (숫자 및 알파벳)뿐만 아니라 좌표를 얻는 방법은 무엇입니까? 예를 들어 10B, 44, 16, 38, 22B 등


텐서 플로우 버전은 무엇입니까? 버전이 2.1 인 경우 2.0
gellezzz

1
나쁜 질문에 바운티를 던지는 것은 좋은 습관이 아닙니다. 이 작업을 수행하는 방법에 대한 지식을 보여주지 않았기 때문에 개발자가 몇 가지 담당자와 교환하여 완벽한 솔루션을 코딩하도록 유혹하는 것처럼 보입니다. 그 이유에 대한 완벽한 답변을 기대하지는 않지만 사람들에게 시간을 지불하면 프리랜서 웹 사이트에서 더 나은 솔루션을 얻을 수 있다고 생각합니다.
karlphillip

@karlphillip 정말 죄송합니다.하지만 초보자가 필요합니다. 맞습니까? 이 일 좀 도와 수
Pulkit Bhatnagar

답변:


13

텍스트가 아닌 윤곽선을 걸러 내기 위해 형태학 연산 을 사용하는 잠재적 인 접근 방식이 있습니다. 아이디어는 다음과 같습니다.

  1. 이진 이미지를 얻습니다. 이미지, 회색조, Otsu의 임계 값 로드

  2. 가로 및 세로 줄을 제거하십시오. 를 사용하여 가로 및 세로 커널을 cv2.getStructuringElement만든 다음cv2.drawContours

  3. 대각선, 원 개체 및 곡선 윤곽을 제거합니다. 비 텍스트 윤곽을 분리하기 위해 윤곽 영역 cv2.contourArea 및 윤곽 근사 cv2.approxPolyDP를 사용하여 필터링

  4. 텍스트 ROI 및 OCR을 추출하십시오. Pytesseract를 사용하여 윤곽선을 찾고 ROI를 필터링 한 다음 OCR을 필터링하십시오 .


녹색으로 강조 표시된 수평선 제거

여기에 이미지 설명을 입력하십시오

수직선 제거

여기에 이미지 설명을 입력하십시오

여러 비 텍스트 윤곽선 (대각선, 원형 객체 및 곡선) 제거

여기에 이미지 설명을 입력하십시오

감지 된 텍스트 영역

여기에 이미지 설명을 입력하십시오

import cv2
import numpy as np
import pytesseract

pytesseract.pytesseract.tesseract_cmd = r"C:\Program Files\Tesseract-OCR\tesseract.exe"

# Load image, grayscale, Otsu's threshold
image = cv2.imread('1.jpg')
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
thresh = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)[1]
clean = thresh.copy()

# Remove horizontal lines
horizontal_kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (15,1))
detect_horizontal = cv2.morphologyEx(thresh, cv2.MORPH_OPEN, horizontal_kernel, iterations=2)
cnts = cv2.findContours(detect_horizontal, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
cnts = cnts[0] if len(cnts) == 2 else cnts[1]
for c in cnts:
    cv2.drawContours(clean, [c], -1, 0, 3)

# Remove vertical lines
vertical_kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (1,30))
detect_vertical = cv2.morphologyEx(thresh, cv2.MORPH_OPEN, vertical_kernel, iterations=2)
cnts = cv2.findContours(detect_vertical, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
cnts = cnts[0] if len(cnts) == 2 else cnts[1]
for c in cnts:
    cv2.drawContours(clean, [c], -1, 0, 3)

cnts = cv2.findContours(clean, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
cnts = cnts[0] if len(cnts) == 2 else cnts[1]
for c in cnts:
    # Remove diagonal lines
    area = cv2.contourArea(c)
    if area < 100:
        cv2.drawContours(clean, [c], -1, 0, 3)
    # Remove circle objects
    elif area > 1000:
        cv2.drawContours(clean, [c], -1, 0, -1)
    # Remove curve stuff
    peri = cv2.arcLength(c, True)
    approx = cv2.approxPolyDP(c, 0.02 * peri, True)
    x,y,w,h = cv2.boundingRect(c)
    if len(approx) == 4:
        cv2.rectangle(clean, (x, y), (x + w, y + h), 0, -1)

open_kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (2,2))
opening = cv2.morphologyEx(clean, cv2.MORPH_OPEN, open_kernel, iterations=2)
close_kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (3,2))
close = cv2.morphologyEx(opening, cv2.MORPH_CLOSE, close_kernel, iterations=4)
cnts = cv2.findContours(close, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
cnts = cnts[0] if len(cnts) == 2 else cnts[1]
for c in cnts:
    x,y,w,h = cv2.boundingRect(c)
    area = cv2.contourArea(c)
    if area > 500:
        ROI = image[y:y+h, x:x+w]
        ROI = cv2.GaussianBlur(ROI, (3,3), 0)
        data = pytesseract.image_to_string(ROI, lang='eng',config='--psm 6')
        if data.isalnum():
            cv2.rectangle(image, (x, y), (x + w, y + h), (36,255,12), 2)
            print(data)

cv2.imwrite('image.png', image)
cv2.imwrite('clean.png', clean)
cv2.imwrite('close.png', close)
cv2.imwrite('opening.png', opening)
cv2.waitKey()

먼저 해당 줄을 제거하는 것이 좋습니다.
Karlphillip

편지의 일부를 제거하는 나쁜 생각 ...
월터 트 로스

8

자, 여기 또 다른 가능한 해결책이 있습니다. 나는 당신이 파이썬으로 일한다는 것을 알고 있습니다-나는 C ++로 일합니다. 나는 당신에게 몇 가지 아이디어를 줄 것이며 희망한다면, 당신 이이 대답을 구현할 수 있기를 바랍니다.

주요 아이디어는 사용하지 않는 것입니다 사전 처리 (적어도하지 초기 단계에서) 전혀 대신 각 대상의 특성에 초점을 일부받을 특성필터링 이 속성에 따라 모든 방울을.

나는 1) 필터와 형태 단계가 얼룩의 품질을 떨어 뜨릴 수 있고 2) 대상 얼룩이 주로 가로 세로 비율면적으로 우리가 활용할 수있는 몇 가지 특성을 나타내는 것처럼 보이기 때문에 전처리를 사용하지 않습니다 .

그것을 확인하십시오, 숫자와 문자는 모두 더 큰 것보다 더 큰 것으로 보입니다 ... 또한, 특정 지역 값 내에서 다양하게 나타납니다. 예를 들어, "너무 넓게" 또는 "너무 크게" 객체를 삭제하려고합니다 .

아이디어는 미리 계산 된 값에 속하지 않는 모든 것을 필터링한다는 것입니다. 문자 (숫자 및 문자)를 검사하고 최소, 최대 영역 값 및 최소 종횡비 (여기서는 높이와 너비의 비율)가 함께 제공되었습니다.

알고리즘 작업을 해보자. 이미지를 읽고 치수의 절반으로 크기를 조정하여 시작하십시오. 이미지가 너무 큽니다. 그레이 스케일로 변환하고 otsu를 통해 이진 이미지를 얻으십시오. 여기 의사 코드가 있습니다.

//Read input:
inputImage = imread( "diagram.png" );

//Resize Image;
resizeScale = 0.5;

inputResized = imresize( inputImage, resizeScale );

//Convert to grayscale;
inputGray = rgb2gray( inputResized );

//Get binary image via otsu:
binaryImage = imbinarize( inputGray, "Otsu" );

멋있는. 이 이미지로 작업하겠습니다. 모든 흰색 얼룩을 검사하고 "속성 필터"를 적용해야합니다 . 통계와 함께 연결된 구성 요소를 사용하여 각 블롭을 루프하고 면적과 종횡비를 얻습니다 .C ++에서는 다음과 같이 수행됩니다.

//Prepare the output matrices:
cv::Mat outputLabels, stats, centroids;
int connectivity = 8;

//Run the binary image through connected components:
int numberofComponents = cv::connectedComponentsWithStats( binaryImage, outputLabels, stats, centroids, connectivity );

//Prepare a vector of colors  color the filtered blobs in black
std::vector<cv::Vec3b> colors(numberofComponents+1);
colors[0] = cv::Vec3b( 0, 0, 0 ); // Element 0 is the background, which remains black.

//loop through the detected blobs:
for( int i = 1; i <= numberofComponents; i++ ) {

    //get area:
    auto blobArea = stats.at<int>(i, cv::CC_STAT_AREA);

    //get height, width and compute aspect ratio:
    auto blobWidth = stats.at<int>(i, cv::CC_STAT_WIDTH);
    auto blobHeight = stats.at<int>(i, cv::CC_STAT_HEIGHT);
    float blobAspectRatio = (float)blobHeight/(float)blobWidth;

    //Filter your blobs

};

이제 속성 필터를 적용하겠습니다. 이것은 미리 계산 된 임계 값과의 비교 일뿐입니다. 다음 값을 사용했습니다.

Minimum Area: 40  Maximum Area:400
MinimumAspectRatio:  1

for루프 내 에서 현재 블롭 속성을이 값과 비교하십시오. 테스트가 긍정적이면 블롭 검정색을 "페인트"합니다. for루프 내부에서 계속 :

    //Filter your blobs

    //Test the current properties against the thresholds:
    bool areaTest =  (blobArea > maxArea)||(blobArea < minArea);
    bool aspectRatioTest = !(blobAspectRatio > minAspectRatio); //notice we are looking for TALL elements!

    //Paint the blob black:
    if( areaTest || aspectRatioTest ){
        //filtered blobs are colored in black:
        colors[i] = cv::Vec3b( 0, 0, 0 );
    }else{
        //unfiltered blobs are colored in white:
        colors[i] = cv::Vec3b( 255, 255, 255 );
    }

루프 후 필터링 된 이미지를 구성하십시오.

cv::Mat filteredMat = cv::Mat::zeros( binaryImage.size(), CV_8UC3 );
for( int y = 0; y < filteredMat.rows; y++ ){
    for( int x = 0; x < filteredMat.cols; x++ )
    {
        int label = outputLabels.at<int>(y, x);
        filteredMat.at<cv::Vec3b>(y, x) = colors[label];
    }
}

그리고… 거의 다 왔습니다. 찾고있는 것과 유사하지 않은 모든 요소를 ​​필터링했습니다. 알고리즘을 실행하면 다음과 같은 결과가 나타납니다.

여기에 이미지 설명을 입력하십시오

또한 결과를 더 잘 시각화하기 위해 blob의 경계 상자를 찾았습니다.

여기에 이미지 설명을 입력하십시오

보시다시피 일부 요소가 감지되지 않습니다. 찾고있는 문자를 더 잘 식별 할 수 있도록 "속성 필터"를 세분화 할 수 있습니다. 약간의 머신 러닝을 포함하는보다 심층적 인 솔루션을 위해서는 "이상적인 특징 벡터"를 구축하고 얼룩에서 특징을 추출하고 유사성 측정을 통해 두 벡터를 비교해야합니다. 또한 사후 처리를 적용 하여 결과를 향상시킬 수 있습니다 ...

어쨌든, 당신의 문제는 사소하지도 않고 쉽게 확장 할 수 없으며, 나는 단지 당신에게 아이디어를주고 있습니다. 다행히도 솔루션을 구현할 수 있기를 바랍니다.


같은 프로그램을 파이썬으로 변환 할 수있는 기회
Pulkit Bhatnagar

@PulkitBhatnagar 물론입니다. 당신은 꽉 잡고 몇 분 안에 완벽한 포트를 준비합니다.
eldesgraciado

?? 내가 당신에게 현상금을 수여하기 위해 그렇게

어 그래. 정말 죄송합니다. 선생님, 문제가 생겼지 만 개종이 잘 진행되고 있습니다. 기다려 고마워.
eldesgraciado

그것이 냉소가 될 수 있는지 궁금하지 않았습니다.
Pulkit Bhatnagar

4

한 가지 방법은 슬라이딩 윈도우를 사용하는 것입니다 (비싸다).

이미지의 문자 크기를 결정하고 (모든 문자가 이미지에서 보이는 것과 동일한 크기 임) 창의 크기를 설정하십시오. 감지를 위해 tesseract를 시도하십시오 (입력 이미지에는 사전 처리가 필요함). 창에서 문자를 연속적으로 감지하면 창의 좌표를 저장하십시오. 좌표를 병합하고 문자의 영역을 가져옵니다.


나는 100bounty가 답을위한 것이라고 생각한다
Himanshu Poddar
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.