ওপেনসিভি পাঠ্য সংগ্রহ করা হচ্ছে


148

আমি একটি চিত্রের পাঠ্যগুলির সীমাবদ্ধ বাক্সগুলি অনুসন্ধান করার চেষ্টা করছি এবং বর্তমানে এই পদ্ধতির ব্যবহার করছি:

// calculate the local variances of the grayscale image
Mat t_mean, t_mean_2;
Mat grayF;
outImg_gray.convertTo(grayF, CV_32F);
int winSize = 35;
blur(grayF, t_mean, cv::Size(winSize,winSize));
blur(grayF.mul(grayF), t_mean_2, cv::Size(winSize,winSize));
Mat varMat = t_mean_2 - t_mean.mul(t_mean);
varMat.convertTo(varMat, CV_8U);

// threshold the high variance regions
Mat varMatRegions = varMat > 100;

যখন এটির মতো একটি চিত্র দেওয়া হয়:

এখানে চিত্র বর্ণনা লিখুন

তারপরে যখন আমি দেখি varMatRegionsআমি এই চিত্রটি পেয়েছি:

এখানে চিত্র বর্ণনা লিখুন

আপনি দেখতে পাচ্ছেন এটি কিছুটা কার্ডের শিরোনামের সাথে টেক্সটের বাম ব্লকটি একত্রিত করে, বেশিরভাগ কার্ডের জন্য এই পদ্ধতিটি দুর্দান্ত কাজ করে তবে ব্যস্ত কার্ডে এটি সমস্যার কারণ হতে পারে।

এই রূপগুলির সংযোগ স্থাপনের পক্ষে খারাপ কারণ হ'ল এটি কনট্যুরের বাউন্ডিং বাক্সটিকে প্রায় পুরো কার্ডটি হাতে নেয়।

পাঠকের সঠিক সনাক্তকরণ নিশ্চিত করার জন্য আমি কী অন্য কোনও উপায়ে পাঠ্যটি সন্ধান করতে পারি?

এই দুটির উপরে কার্ডে যে কেউ পাঠ্যটি খুঁজে পেতে পারে তার প্রতি 200 পয়েন্ট।

এখানে চিত্র বর্ণনা লিখুন এখানে চিত্র বর্ণনা লিখুন


1
আমি এখানে দেখার সবচেয়ে সহজ উপায় অঞ্চলগুলি পাওয়ার আগে বৈপরীত্যকে বাড়িয়ে দিচ্ছি ...
পায়েভ স্টাওয়ার্জ

3
দুর্দান্ত প্রশ্ন। এটিকে আকর্ষণীয় উত্তরগুলি নিশ্চিত করার জন্য এটি পোস্ট এবং অনুগ্রহটি হোস্ট করার জন্য ধন্যবাদ।
জেফ

প্রোগ্রামিং নতুন। সংস্কৃতের মতো ইংরেজি ছাড়া অন্য স্ক্রিপ্টগুলিতেও কি একই জিনিসগুলি করা যায়?
বামশি কৃষ্ণ

উত্তর:


127

আপনি কাছের প্রান্ত উপাদানগুলি (একটি এলপডি থেকে অনুপ্রাণিত) সন্ধান করে পাঠ্য সনাক্ত করতে পারবেন:

#include "opencv2/opencv.hpp"

std::vector<cv::Rect> detectLetters(cv::Mat img)
{
    std::vector<cv::Rect> boundRect;
    cv::Mat img_gray, img_sobel, img_threshold, element;
    cvtColor(img, img_gray, CV_BGR2GRAY);
    cv::Sobel(img_gray, img_sobel, CV_8U, 1, 0, 3, 1, 0, cv::BORDER_DEFAULT);
    cv::threshold(img_sobel, img_threshold, 0, 255, CV_THRESH_OTSU+CV_THRESH_BINARY);
    element = getStructuringElement(cv::MORPH_RECT, cv::Size(17, 3) );
    cv::morphologyEx(img_threshold, img_threshold, CV_MOP_CLOSE, element); //Does the trick
    std::vector< std::vector< cv::Point> > contours;
    cv::findContours(img_threshold, contours, 0, 1); 
    std::vector<std::vector<cv::Point> > contours_poly( contours.size() );
    for( int i = 0; i < contours.size(); i++ )
        if (contours[i].size()>100)
        { 
            cv::approxPolyDP( cv::Mat(contours[i]), contours_poly[i], 3, true );
            cv::Rect appRect( boundingRect( cv::Mat(contours_poly[i]) ));
            if (appRect.width>appRect.height) 
                boundRect.push_back(appRect);
        }
    return boundRect;
}

ব্যবহার:

int main(int argc,char** argv)
{
    //Read
    cv::Mat img1=cv::imread("side_1.jpg");
    cv::Mat img2=cv::imread("side_2.jpg");
    //Detect
    std::vector<cv::Rect> letterBBoxes1=detectLetters(img1);
    std::vector<cv::Rect> letterBBoxes2=detectLetters(img2);
    //Display
    for(int i=0; i< letterBBoxes1.size(); i++)
        cv::rectangle(img1,letterBBoxes1[i],cv::Scalar(0,255,0),3,8,0);
    cv::imwrite( "imgOut1.jpg", img1);  
    for(int i=0; i< letterBBoxes2.size(); i++)
        cv::rectangle(img2,letterBBoxes2[i],cv::Scalar(0,255,0),3,8,0);
    cv::imwrite( "imgOut2.jpg", img2);  
    return 0;
}

ফলাফল:

ক। উপাদান = getStructuringElement (cv :: MORPH_RECT, cv :: আকার (17, 3)); imgOut1 imgOut2

খ। উপাদান = getStructuringElement (সিভি :: MORPH_RECT, সিভি :: আকার (30, 30)); imgOut1 imgOut2

উল্লিখিত অন্যান্য চিত্রের জন্য ফলাফলগুলি একই রকম।


6
লাইসেন্স প্লেট সনাক্তকারী।
লোভাবিলে

2
কিছু কার্ডের জন্য বাউন্ডিং বক্স সমস্ত পাঠ্যকে আবদ্ধ করে না, যেমন অর্ধেক চিঠিটি কেটে ফেলা হয়। যেমন এই কার্ড: i.imgur.com/tX3XrwH.jpg আমি প্রতিটি বাউন্ডিং বাউন্ডিং বাক্সগুলির উচ্চতা এবং প্রস্থকে কীভাবে প্রসারিত করতে পারি n? সমাধানটি দুর্দান্ত কাজ করার জন্য ধন্যবাদ!
ক্লিপ

4
বলুন cv::Rect a;। N দ্বারা বৃহদাকার: a.x-=n/2;a.y-=n/2;a.width+=n;a.height+=n;
লোভাবিল 12'14

2
হাই, পাইথন সিভি 2 দিয়ে আমি কীভাবে একই ফলাফল অর্জন করব?
dnth


128

আমি নীচের প্রোগ্রামে গ্রেডিয়েন্ট ভিত্তিক পদ্ধতি ব্যবহার করেছি। ফলস্বরূপ চিত্রগুলি যুক্ত করা হয়েছে। দয়া করে নোট করুন যে আমি প্রসেসিংয়ের জন্য চিত্রটির একটি ছোট আকারের সংস্করণ ব্যবহার করছি।

সি ++ সংস্করণ

The MIT License (MIT)

Copyright (c) 2014 Dhanushka Dangampola

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

#include "stdafx.h"

#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <iostream>

using namespace cv;
using namespace std;

#define INPUT_FILE              "1.jpg"
#define OUTPUT_FOLDER_PATH      string("")

int _tmain(int argc, _TCHAR* argv[])
{
    Mat large = imread(INPUT_FILE);
    Mat rgb;
    // downsample and use it for processing
    pyrDown(large, rgb);
    Mat small;
    cvtColor(rgb, small, CV_BGR2GRAY);
    // morphological gradient
    Mat grad;
    Mat morphKernel = getStructuringElement(MORPH_ELLIPSE, Size(3, 3));
    morphologyEx(small, grad, MORPH_GRADIENT, morphKernel);
    // binarize
    Mat bw;
    threshold(grad, bw, 0.0, 255.0, THRESH_BINARY | THRESH_OTSU);
    // connect horizontally oriented regions
    Mat connected;
    morphKernel = getStructuringElement(MORPH_RECT, Size(9, 1));
    morphologyEx(bw, connected, MORPH_CLOSE, morphKernel);
    // find contours
    Mat mask = Mat::zeros(bw.size(), CV_8UC1);
    vector<vector<Point>> contours;
    vector<Vec4i> hierarchy;
    findContours(connected, contours, hierarchy, CV_RETR_CCOMP, CV_CHAIN_APPROX_SIMPLE, Point(0, 0));
    // filter contours
    for(int idx = 0; idx >= 0; idx = hierarchy[idx][0])
    {
        Rect rect = boundingRect(contours[idx]);
        Mat maskROI(mask, rect);
        maskROI = Scalar(0, 0, 0);
        // fill the contour
        drawContours(mask, contours, idx, Scalar(255, 255, 255), CV_FILLED);
        // ratio of non-zero pixels in the filled region
        double r = (double)countNonZero(maskROI)/(rect.width*rect.height);

        if (r > .45 /* assume at least 45% of the area is filled if it contains text */
            && 
            (rect.height > 8 && rect.width > 8) /* constraints on region size */
            /* these two conditions alone are not very robust. better to use something 
            like the number of significant peaks in a horizontal projection as a third condition */
            )
        {
            rectangle(rgb, rect, Scalar(0, 255, 0), 2);
        }
    }
    imwrite(OUTPUT_FOLDER_PATH + string("rgb.jpg"), rgb);

    return 0;
}

পাইথন সংস্করণ

The MIT License (MIT)

Copyright (c) 2017 Dhanushka Dangampola

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

import cv2
import numpy as np

large = cv2.imread('1.jpg')
rgb = cv2.pyrDown(large)
small = cv2.cvtColor(rgb, cv2.COLOR_BGR2GRAY)

kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (3, 3))
grad = cv2.morphologyEx(small, cv2.MORPH_GRADIENT, kernel)

_, bw = cv2.threshold(grad, 0.0, 255.0, cv2.THRESH_BINARY | cv2.THRESH_OTSU)

kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (9, 1))
connected = cv2.morphologyEx(bw, cv2.MORPH_CLOSE, kernel)
# using RETR_EXTERNAL instead of RETR_CCOMP
contours, hierarchy = cv2.findContours(connected.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)
#For opencv 3+ comment the previous line and uncomment the following line
#_, contours, hierarchy = cv2.findContours(connected.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)

mask = np.zeros(bw.shape, dtype=np.uint8)

for idx in range(len(contours)):
    x, y, w, h = cv2.boundingRect(contours[idx])
    mask[y:y+h, x:x+w] = 0
    cv2.drawContours(mask, contours, idx, (255, 255, 255), -1)
    r = float(cv2.countNonZero(mask[y:y+h, x:x+w])) / (w * h)

    if r > 0.45 and w > 8 and h > 8:
        cv2.rectangle(rgb, (x, y), (x+w-1, y+h-1), (0, 255, 0), 2)

cv2.imshow('rects', rgb)

এখানে চিত্র বর্ণনা লিখুন এখানে চিত্র বর্ণনা লিখুন এখানে চিত্র বর্ণনা লিখুন


3
আমি শুধু তার পদ্ধতির এক নজর ছিল। আমি দেখতে পাচ্ছি প্রধান পার্থক্য হ'ল তিনি একটি সোবেল ফিল্টার ব্যবহার করছেন যখন আমি মরফোলজিকাল গ্রেডিয়েন্ট ফিল্টার ব্যবহার করছি। আমি মনে করি যে রূপক ফিল্টার এবং ডাউনসাম্পলিং-তেমন শক্তিশালী নয় এমন প্রান্তগুলি অনেকাংশে সমতল করে। সোবেল আরও শব্দ করতে পারে।
ধনুশকা

1
@ এসেনেটর আপনি যখন প্রান্তিক প্রকারের সাথে ওটিএসইউ একত্রিত করেন, তখন এটি নির্দিষ্ট থ্রোসোল্ড মানের পরিবর্তে অটসুর প্রান্তিক ব্যবহার করে। এখানে দেখুন ।
ধনুশকা

1
@ বিষ্ণুজায়ানন্দ আপনাকে কেবলমাত্র একটি স্কেলিং প্রয়োগ করতে হবে rect। একটি আছে pyrdown, তাই 4 x, y, width, heightদিয়ে গুণ করুনrect
ধনুশকা

1
আপনি দয়া করে আমাদের তৃতীয় শর্তটি সরবরাহ করতে পারেন: অনুভূমিক প্রক্ষেপণে বা কমপক্ষে কিছু সীসাতে উল্লেখযোগ্য শিখর সংখ্যা।
ইসলিমনি

2
@ ডিফোরটাই ভরাট কনট্যুরের অনুভূমিক প্রজেকশনটি নিন (সিভি :: হ্রাস), তারপরে এটি প্রসারিত করুন (বলুন, গড় বা মাঝারি উচ্চতা ব্যবহার করে)। আপনি যদি এই ফলাফলটি কল্পনা করেন তবে এটি বারকোডের মতো দেখাবে। আমি মনে করি, সেই সময়, আমি বারগুলির সংখ্যা গণনা এবং এটির উপরে একটি দোরত্ব চাপানোর কথা ভাবছিলাম। এখন আমি মনে করি, অঞ্চলটি যদি যথেষ্ট পরিচ্ছন্ন থাকে তবে এটি যদি ওসিআরকে খাওয়ানো যায় এবং প্রতিটি সনাক্ত করা চরিত্রের জন্য একটি আস্থা স্তর অর্জন করতে পারে যে অঞ্চলে পাঠ্য রয়েছে তা নিশ্চিত হতে সহায়তা করতে পারে।
ধনুশকা

51

এখানে একটি বিকল্প পদ্ধতি যা আমি পাঠ্য ব্লকগুলি সনাক্ত করতে ব্যবহার করেছি:

  1. চিত্রটিকে গ্রেস্কেলে রূপান্তরিত করা হয়েছে
  2. প্রয়োগিত থ্রেশহোল্ড (প্রান্তিক মান হিসাবে 150 এর হ্যান্ডপিকড মান সহ সাধারণ বাইনারি থ্রেশহোল্ড)
  3. চিত্রটিতে ঘন রেখাগুলিতে প্রসারণ প্রয়োগ করা হয়েছে, এতে আরও কমপ্যাক্ট অবজেক্ট এবং কম সাদা স্থানের টুকরোগুলি রয়েছে। পুনরাবৃত্তির সংখ্যার জন্য একটি উচ্চ মানের ব্যবহৃত হয়, তাই প্রসারণ খুব ভারী (13 পুনরাবৃত্তি, অনুকূল ফলাফলের জন্য হ্যান্ডপিকযুক্ত)।
  4. ওপেনসিভি ফাইড কনট্যুরস ফাংশন ব্যবহার করে ফলাফলের চিত্রটিতে অবজেক্টগুলির সংক্ষিপ্তসার সনাক্ত করা।
  5. প্রতিটি কনট্যুর করা অবজেক্টকে সাবস্ক্রাইব করে একটি বাউন্ডিং বক্স (আয়তক্ষেত্র) আঁকুন - তাদের প্রত্যেকটি পাঠ্যের একটি ব্লক ফ্রেম করে।
  6. Sizeচ্ছিকভাবে ফেলে দেওয়া অঞ্চলগুলি যা আকার হিসাবে আপনি (যেমন টেক্সট ব্লকগুলি) অনুসন্ধান করছেন সেটির সম্ভাবনা নেই, কারণ উপরের অ্যালগরিদমটি ছেদযুক্ত বা নেস্টেড বস্তুগুলি (প্রথম কার্ডের জন্য পুরো শীর্ষ অঞ্চলগুলির মতো) খুঁজে পেতে পারে যার মধ্যে কিছু হতে পারে আপনার উদ্দেশ্য জন্য উদাসীন।

নীচে পাইপেনসিভিতে পাইথনটিতে লিখিত কোডটি দেওয়া হয়েছে, সি ++ তে পোর্ট করা সহজ হওয়া উচিত।

import cv2

image = cv2.imread("card.png")
gray = cv2.cvtColor(image,cv2.COLOR_BGR2GRAY) # grayscale
_,thresh = cv2.threshold(gray,150,255,cv2.THRESH_BINARY_INV) # threshold
kernel = cv2.getStructuringElement(cv2.MORPH_CROSS,(3,3))
dilated = cv2.dilate(thresh,kernel,iterations = 13) # dilate
_, contours, hierarchy = cv2.findContours(dilated,cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_NONE) # get contours

# for each contour found, draw a rectangle around it on original image
for contour in contours:
    # get rectangle bounding contour
    [x,y,w,h] = cv2.boundingRect(contour)

    # discard areas that are too large
    if h>300 and w>300:
        continue

    # discard areas that are too small
    if h<40 or w<40:
        continue

    # draw rectangle around contour on original image
    cv2.rectangle(image,(x,y),(x+w,y+h),(255,0,255),2)

# write original image with added contours to disk  
cv2.imwrite("contoured.jpg", image) 

আসল চিত্রটি আপনার পোস্টের প্রথম চিত্র।

প্রিপ্রোসেসিংয়ের পরে (গ্রেস্কেল, প্রান্তিক এবং ডায়লেট - সুতরাং ৩ য় পদক্ষেপের পরে) চিত্রটি দেখতে এমন দেখাচ্ছে:

ছড়িয়ে ছিটিয়ে থাকা চিত্র

নীচে ফলাফল চিত্র (শেষ লাইনে "contour.jpg"); চিত্রটিতে থাকা অবজেক্টগুলির জন্য চূড়ান্ত সীমানা বাক্সগুলি এর মতো দেখাচ্ছে:

এখানে চিত্র বর্ণনা লিখুন

আপনি দেখতে পাচ্ছেন যে বামপাশের পাঠ্য ব্লকটি একটি পৃথক ব্লক হিসাবে সনাক্ত করা হয়েছে, এর চারপাশ থেকে সীমাবদ্ধ।

একই প্যারামিটারগুলির সাথে একই স্ক্রিপ্ট ব্যবহার করে (নীচে বর্ণিত মত দ্বিতীয় চিত্রের জন্য পরিবর্তিত থ্রেশোল্ডিং টাইপ ব্যতীত), অন্যান্য 2 টি কার্ডের ফলাফল এখানে রয়েছে:

এখানে চিত্র বর্ণনা লিখুন

এখানে চিত্র বর্ণনা লিখুন

পরামিতিগুলি টিউন করছে

প্যারামিটারগুলি (প্রান্তিক মান, প্রসার পরামিতি) এই চিত্র এবং এই টাস্কের জন্য (টেক্সট ব্লকগুলি সন্ধান করা) অপ্টিমাইজ করা হয়েছিল এবং অন্যান্য কার্ডের চিত্র বা অন্যান্য ধরণের অবজেক্ট সন্ধানের জন্য প্রয়োজন হলে সামঞ্জস্য করা যেতে পারে।

থ্রেশহোল্ডিংয়ের জন্য (পদক্ষেপ 2), আমি একটি কালো থ্রেশহোল্ড ব্যবহার করেছি। চিত্রগুলির জন্য যেখানে পাঠ্যটি পটভূমির চেয়ে হালকা, যেমন আপনার পোস্টের দ্বিতীয় চিত্র হিসাবে একটি সাদা থ্রোসোল্ড ব্যবহার করা উচিত, সুতরাং এর সাথে থোল্ডিংয়ের ধরনটি প্রতিস্থাপন করুন cv2.THRESH_BINARY)। দ্বিতীয় চিত্রের জন্য আমি প্রান্তিকের জন্যও কিছুটা বেশি মান ব্যবহার করেছি (180)। প্রান্তিক মানের জন্য পরামিতিগুলির পরিবর্তন এবং প্রসারণের জন্য পুনরাবৃত্তির সংখ্যার ফলে চিত্রের সীমানাঙ্কিত বস্তুগুলিতে সংবেদনশীলতার বিভিন্ন ডিগ্রি হবে।

অন্যান্য বস্তুর প্রকারগুলি সন্ধান করা:

উদাহরণস্বরূপ, প্রথম চিত্রের মধ্যে বিশিষ্টতা 5 টি পুনরাবৃত্তিতে হ্রাস করা আমাদের চিত্রের অবজেক্টগুলির আরও সূক্ষ্ম বিস্মরণ দেয়, মোটামুটি চিত্রটিতে সমস্ত শব্দ খুঁজে পাওয়া যায় (পাঠ্য ব্লকগুলির চেয়ে):

এখানে চিত্র বর্ণনা লিখুন

শব্দের মোটামুটি আকার সম্পর্কে জানার জন্য, আমি এখানে এমন ক্ষেত্রগুলি বাতিল করেছি যেগুলি খুব ছোট (20 পিক্সেলের প্রস্থ বা উচ্চতার নীচে) বা খুব বড় (100 পিক্সেলের প্রস্থ বা উচ্চতার উপরে) শব্দের সম্ভাবনা নেই এমন বিষয়গুলিকে উপেক্ষা করার জন্য, ফলাফলগুলি পেতে উপরের চিত্র


2
তুমি চমৎকার! আমি সকালে এটি চেষ্টা করব।
ক্লিপ

আমি উদ্বেগজনক জিনিসগুলি ত্যাগ করার জন্য আরও একটি পদক্ষেপ যুক্ত করেছি; শব্দ বা অন্যান্য ধরণের অবজেক্ট (পাঠ্যের ব্লক ব্যতীত) সনাক্ত করার জন্য উদাহরণও যুক্ত করেছে
আনানা

বিস্তারিত উত্তরের জন্য ধন্যবাদ, তবে আমি এতে একটি ত্রুটি পাচ্ছি cv2.findContours। এটা বলে ValueError: too many values to unpack
অভিজিৎ

1
বিষয়টি হ'ল ফাংশনটি cv2.findContours3 টি যুক্তি দেয় এবং মূল কোডটি কেবল 2 টি ধারণ করে
অভিজিৎ

@ দ্বিতীয় সংস্করণে আজিজিথ সিভি 2 দুটি আর্গ ফিরে এনেছে, তবে এখন, তিন সংস্করণে এটি 3 ফেরত আসে
টমাসজ গিবা

27

@ ধনুশকার যোগাযোগটি সর্বাধিক প্রতিশ্রুতি দেখিয়েছে তবে আমি পাইথনের আশেপাশে খেলতে চেয়েছিলাম তাই এগিয়ে গিয়ে মজাদার জন্য অনুবাদ করেছি:

import cv2
import numpy as np
from cv2 import boundingRect, countNonZero, cvtColor, drawContours, findContours, getStructuringElement, imread, morphologyEx, pyrDown, rectangle, threshold

large = imread(image_path)
# downsample and use it for processing
rgb = pyrDown(large)
# apply grayscale
small = cvtColor(rgb, cv2.COLOR_BGR2GRAY)
# morphological gradient
morph_kernel = getStructuringElement(cv2.MORPH_ELLIPSE, (3, 3))
grad = morphologyEx(small, cv2.MORPH_GRADIENT, morph_kernel)
# binarize
_, bw = threshold(src=grad, thresh=0, maxval=255, type=cv2.THRESH_BINARY+cv2.THRESH_OTSU)
morph_kernel = getStructuringElement(cv2.MORPH_RECT, (9, 1))
# connect horizontally oriented regions
connected = morphologyEx(bw, cv2.MORPH_CLOSE, morph_kernel)
mask = np.zeros(bw.shape, np.uint8)
# find contours
im2, contours, hierarchy = findContours(connected, cv2.RETR_CCOMP, cv2.CHAIN_APPROX_SIMPLE)
# filter contours
for idx in range(0, len(hierarchy[0])):
    rect = x, y, rect_width, rect_height = boundingRect(contours[idx])
    # fill the contour
    mask = drawContours(mask, contours, idx, (255, 255, 2555), cv2.FILLED)
    # ratio of non-zero pixels in the filled region
    r = float(countNonZero(mask)) / (rect_width * rect_height)
    if r > 0.45 and rect_height > 8 and rect_width > 8:
        rgb = rectangle(rgb, (x, y+rect_height), (x+rect_width, y), (0,255,0),3)

এখন চিত্রটি প্রদর্শন করতে:

from PIL import Image
Image.fromarray(rgb).show()

স্ক্রিপ্টগুলির সর্বাধিক পাইথোনিক নয় তবে আমি পাঠকদের অনুসরণ করার জন্য যথাসম্ভব ঘনিষ্ঠভাবে মূল সি ++ কোডের সাদৃশ্য করার চেষ্টা করেছি।

এটি প্রায় পাশাপাশি মূল হিসাবে কাজ করে। মূল ফলাফলগুলি সম্পূর্ণরূপে সাদৃশ্য করার জন্য কীভাবে এটি উন্নত / স্থির করা যেতে পারে তার পরামর্শগুলি পড়তে আমি খুশি হব।

এখানে চিত্র বর্ণনা লিখুন

এখানে চিত্র বর্ণনা লিখুন

এখানে চিত্র বর্ণনা লিখুন


3
অজগর সংস্করণ সরবরাহ করার জন্য আপনাকে ধন্যবাদ। অনেক লোক এটি দরকারী খুঁজে পাবেন। +1
ধনুশকা

কনট্যুর পূরণ এবং এটি আঁকার মধ্যে পার্থক্য কি? : আমি এখানে ভর্তি ফেজ ছাড়া একটি কোড পাওয়া stackoverflow.com/a/23556997/6837132
SarahData

@ সারাহম আমি জানি না আপনি অঙ্কন এবং ফিলিংয়ের মধ্যে জেনেরিক পার্থক্য সম্পর্কে জিজ্ঞাসা করছেন (বিশেষত আমার মনে হয়?) বা ওপেনসিভি এপিআই বিশেষত? যদি দ্বিতীয়টি থাকে তবে সেই স্থিতির জন্য ডকগুলি দেখুন drawContours"ফাংশনটি বেধ> 0 হলে চিত্রে কনট্যুর রূপরেখা অঙ্কন করে বা বেধ <0. 0 হলে সংক্ষিপ্তসার দ্বারা আবদ্ধ অঞ্চলটি পূরণ করে" এটি সম্পন্ন হয়েছে যাতে বাক্সে সম্ভবত পাঠ্য রয়েছে কিনা তা সিদ্ধান্ত নিতে আমরা শূন্য-পিক্সেলের অনুপাত পরীক্ষা করতে পারি।
rtkaleta

15

আপনি এই পদ্ধতিটি চেষ্টা করতে পারেন যা চুচাই ই এবং ইংলি টিয়ান দ্বারা বিকাশ করা হয়েছে।

তারা এমন একটি সফ্টওয়্যার ভাগ করে (যা ওপেনসিভি -১.০ ভিত্তিক এবং এটি উইন্ডোজ প্ল্যাটফর্মের অধীনে চলতে হবে)) যা আপনি ব্যবহার করতে পারেন (যদিও কোনও উত্স কোড উপলব্ধ নেই)। এটি চিত্রের সমস্ত পাঠ্য বাউন্ডিং বক্স (রঙের ছায়ায় দেখানো) তৈরি করবে। আপনার নমুনা চিত্রগুলিতে প্রয়োগ করে, আপনি নিম্নলিখিত ফলাফলগুলি পাবেন:

দ্রষ্টব্য: ফলাফলটিকে আরও দৃust় করতে আপনি আরও সংলগ্ন বাক্সগুলিকে একত্রে মার্জ করতে পারেন।


আপডেট: যদি আপনার চূড়ান্ত লক্ষ্য চিত্রটির পাঠ্যগুলি চিহ্নিত করা হয় তবে আপনি আরও gttext পরীক্ষা করতে পারেন , এটি একটি ওসিআর মুক্ত সফ্টওয়্যার এবং পাঠ্য সহ রঙিন চিত্রগুলির জন্য গ্রাউন্ড ট্রুথিং সরঞ্জাম। উত্স কোডও উপলব্ধ।

এটির সাহায্যে আপনি স্বীকৃত পাঠ্যগুলি পেতে পারেন:


gttext উইন্ডোজ জন্য। ম্যাক / লিনাক্স ব্যবহারকারীদের জন্য কোনও পরামর্শ
সগির এ। খাত্রি

5

কোড জাভা সংস্করণের উপরে: ধন্যবাদ @ উইলিয়াম

public static List<Rect> detectLetters(Mat img){    
    List<Rect> boundRect=new ArrayList<>();

    Mat img_gray =new Mat(), img_sobel=new Mat(), img_threshold=new Mat(), element=new Mat();
    Imgproc.cvtColor(img, img_gray, Imgproc.COLOR_RGB2GRAY);
    Imgproc.Sobel(img_gray, img_sobel, CvType.CV_8U, 1, 0, 3, 1, 0, Core.BORDER_DEFAULT);
    //at src, Mat dst, double thresh, double maxval, int type
    Imgproc.threshold(img_sobel, img_threshold, 0, 255, 8);
    element=Imgproc.getStructuringElement(Imgproc.MORPH_RECT, new Size(15,5));
    Imgproc.morphologyEx(img_threshold, img_threshold, Imgproc.MORPH_CLOSE, element);
    List<MatOfPoint> contours = new ArrayList<MatOfPoint>();
    Mat hierarchy = new Mat();
    Imgproc.findContours(img_threshold, contours,hierarchy, 0, 1);

    List<MatOfPoint> contours_poly = new ArrayList<MatOfPoint>(contours.size());

     for( int i = 0; i < contours.size(); i++ ){             

         MatOfPoint2f  mMOP2f1=new MatOfPoint2f();
         MatOfPoint2f  mMOP2f2=new MatOfPoint2f();

         contours.get(i).convertTo(mMOP2f1, CvType.CV_32FC2);
         Imgproc.approxPolyDP(mMOP2f1, mMOP2f2, 2, true); 
         mMOP2f2.convertTo(contours.get(i), CvType.CV_32S);


            Rect appRect = Imgproc.boundingRect(contours.get(i));
            if (appRect.width>appRect.height) {
                boundRect.add(appRect);
            }
     }

    return boundRect;
}

এবং অনুশীলনে এই কোডটি ব্যবহার করুন:

        System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
        Mat img1=Imgcodecs.imread("abc.png");
        List<Rect> letterBBoxes1=Utils.detectLetters(img1);

        for(int i=0; i< letterBBoxes1.size(); i++)
            Imgproc.rectangle(img1,letterBBoxes1.get(i).br(), letterBBoxes1.get(i).tl(),new Scalar(0,255,0),3,8,0);         
        Imgcodecs.imwrite("abc1.png", img1);

2

@ ধনুশকার সমাধানের জন্য পাইথন বাস্তবায়ন:

def process_rgb(rgb):
    hasText = False
    gray = cv2.cvtColor(rgb, cv2.COLOR_BGR2GRAY)
    morphKernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (3,3))
    grad = cv2.morphologyEx(gray, cv2.MORPH_GRADIENT, morphKernel)
    # binarize
    _, bw = cv2.threshold(grad, 0.0, 255.0, cv2.THRESH_BINARY | cv2.THRESH_OTSU)
    # connect horizontally oriented regions
    morphKernel = cv2.getStructuringElement(cv2.MORPH_RECT, (9, 1))
    connected = cv2.morphologyEx(bw, cv2.MORPH_CLOSE, morphKernel)
    # find contours
    mask = np.zeros(bw.shape[:2], dtype="uint8")
    _,contours, hierarchy = cv2.findContours(connected, cv2.RETR_CCOMP, cv2.CHAIN_APPROX_SIMPLE)
    # filter contours
    idx = 0
    while idx >= 0:
        x,y,w,h = cv2.boundingRect(contours[idx])
        # fill the contour
        cv2.drawContours(mask, contours, idx, (255, 255, 255), cv2.FILLED)
        # ratio of non-zero pixels in the filled region
        r = cv2.contourArea(contours[idx])/(w*h)
        if(r > 0.45 and h > 5 and w > 5 and w > h):
            cv2.rectangle(rgb, (x,y), (x+w,y+h), (0, 255, 0), 2)
            hasText = True
        idx = hierarchy[0][idx][0]
    return hasText, rgb

কেন মুখোশ ব্যবহার?
সারাটাটা

1
সদৃশ উত্তর। আপনি যদি স্ট্যাকওভারফ্লো . com/a/43283990/6809909 এ কথোপকথনে অবদান রাখেন তবে এটি আরও কার্যকর হত ।
rtkaleta

2

এটি ওপেনসিভিশার্প ব্যবহার করে ধনুশকের উত্তরের সি # সংস্করণ

        Mat large = new Mat(INPUT_FILE);
        Mat rgb = new Mat(), small = new Mat(), grad = new Mat(), bw = new Mat(), connected = new Mat();

        // downsample and use it for processing
        Cv2.PyrDown(large, rgb);
        Cv2.CvtColor(rgb, small, ColorConversionCodes.BGR2GRAY);

        // morphological gradient
        var morphKernel = Cv2.GetStructuringElement(MorphShapes.Ellipse, new OpenCvSharp.Size(3, 3));
        Cv2.MorphologyEx(small, grad, MorphTypes.Gradient, morphKernel);

        // binarize
        Cv2.Threshold(grad, bw, 0, 255, ThresholdTypes.Binary | ThresholdTypes.Otsu);

        // connect horizontally oriented regions
        morphKernel = Cv2.GetStructuringElement(MorphShapes.Rect, new OpenCvSharp.Size(9, 1));
        Cv2.MorphologyEx(bw, connected, MorphTypes.Close, morphKernel);

        // find contours
        var mask = new Mat(Mat.Zeros(bw.Size(), MatType.CV_8UC1), Range.All);
        Cv2.FindContours(connected, out OpenCvSharp.Point[][] contours, out HierarchyIndex[] hierarchy, RetrievalModes.CComp, ContourApproximationModes.ApproxSimple, new OpenCvSharp.Point(0, 0));

        // filter contours
        var idx = 0;
        foreach (var hierarchyItem in hierarchy)
        {
            idx = hierarchyItem.Next;
            if (idx < 0)
                break;
            OpenCvSharp.Rect rect = Cv2.BoundingRect(contours[idx]);
            var maskROI = new Mat(mask, rect);
            maskROI.SetTo(new Scalar(0, 0, 0));

            // fill the contour
            Cv2.DrawContours(mask, contours, idx, Scalar.White, -1);

            // ratio of non-zero pixels in the filled region
            double r = (double)Cv2.CountNonZero(maskROI) / (rect.Width * rect.Height);
            if (r > .45 /* assume at least 45% of the area is filled if it contains text */
                 &&
            (rect.Height > 8 && rect.Width > 8) /* constraints on region size */
            /* these two conditions alone are not very robust. better to use something 
            like the number of significant peaks in a horizontal projection as a third condition */
            )
            {
                Cv2.Rectangle(rgb, rect, new Scalar(0, 255, 0), 2);
            }
        }

        rgb.SaveImage(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "rgb.jpg"));

0

এই একটি VB.NET সংস্করণ উত্তর dhanushka ব্যবহার থেকে EmguCV

এমগুভিভিতে কয়েকটি ফাংশন এবং কাঠামোর ওপেনসিভিশার্প সহ সি # সংস্করণের চেয়ে আলাদা বিবেচনা প্রয়োজন consideration

Imports Emgu.CV
Imports Emgu.CV.Structure
Imports Emgu.CV.CvEnum
Imports Emgu.CV.Util

        Dim input_file As String = "C:\your_input_image.png"
        Dim large As Mat = New Mat(input_file)
        Dim rgb As New Mat
        Dim small As New Mat
        Dim grad As New Mat
        Dim bw As New Mat
        Dim connected As New Mat
        Dim morphanchor As New Point(0, 0)

        '//downsample and use it for processing
        CvInvoke.PyrDown(large, rgb)
        CvInvoke.CvtColor(rgb, small, ColorConversion.Bgr2Gray)

        '//morphological gradient
        Dim morphKernel As Mat = CvInvoke.GetStructuringElement(ElementShape.Ellipse, New Size(3, 3), morphanchor)
        CvInvoke.MorphologyEx(small, grad, MorphOp.Gradient, morphKernel, New Point(0, 0), 1, BorderType.Isolated, New MCvScalar(0))

        '// binarize
        CvInvoke.Threshold(grad, bw, 0, 255, ThresholdType.Binary Or ThresholdType.Otsu)

        '// connect horizontally oriented regions
        morphKernel = CvInvoke.GetStructuringElement(ElementShape.Rectangle, New Size(9, 1), morphanchor)
        CvInvoke.MorphologyEx(bw, connected, MorphOp.Close, morphKernel, morphanchor, 1, BorderType.Isolated, New MCvScalar(0))

        '// find contours
        Dim mask As Mat = Mat.Zeros(bw.Size.Height, bw.Size.Width, DepthType.Cv8U, 1)  '' MatType.CV_8UC1
        Dim contours As New VectorOfVectorOfPoint
        Dim hierarchy As New Mat

        CvInvoke.FindContours(connected, contours, hierarchy, RetrType.Ccomp, ChainApproxMethod.ChainApproxSimple, Nothing)

        '// filter contours
        Dim idx As Integer
        Dim rect As Rectangle
        Dim maskROI As Mat
        Dim r As Double
        For Each hierarchyItem In hierarchy.GetData
            rect = CvInvoke.BoundingRectangle(contours(idx))
            maskROI = New Mat(mask, rect)
            maskROI.SetTo(New MCvScalar(0, 0, 0))

            '// fill the contour
            CvInvoke.DrawContours(mask, contours, idx, New MCvScalar(255), -1)

            '// ratio of non-zero pixels in the filled region
            r = CvInvoke.CountNonZero(maskROI) / (rect.Width * rect.Height)

            '/* assume at least 45% of the area Is filled if it contains text */
            '/* constraints on region size */
            '/* these two conditions alone are Not very robust. better to use something 
            'Like the number of significant peaks in a horizontal projection as a third condition */
            If r > 0.45 AndAlso rect.Height > 8 AndAlso rect.Width > 8 Then
                'draw green rectangle
                CvInvoke.Rectangle(rgb, rect, New MCvScalar(0, 255, 0), 2)
            End If
            idx += 1
        Next
        rgb.Save(IO.Path.Combine(Application.StartupPath, "rgb.jpg"))
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.