ওপেনসিভি-পাইথনে সাধারণ ডিজিট স্বীকৃতি ওসিআর


380

আমি ওপেনসিভি-পাইথন (সিভি 2) এ একটি "ডিজিট রিকগনিশন ওসিআর" প্রয়োগ করার চেষ্টা করছি। এটি কেবল শেখার উদ্দেশ্যে। আমি ওপেনসিভিতে কে নেরেস্ট এবং এসভিএম বৈশিষ্ট্য উভয়ই শিখতে চাই।

আমার কাছে প্রতিটি অঙ্কের 100 টি নমুনা (অর্থাত্ চিত্র) রয়েছে। আমি তাদের সাথে প্রশিক্ষণ চাই।

letter_recog.pyওপেনসিভি নমুনার সাথে একটি নমুনা আসে। তবে কীভাবে এটি ব্যবহার করবেন তা আমি এখনও বুঝতে পারি না। আমি বুঝতে পারি না কী কী নমুনা, প্রতিক্রিয়া ইত্যাদি Also এছাড়াও, এটি প্রথমে একটি txt ফাইল লোড করে, যা আমি প্রথমে বুঝতে পারি নি।

পরে কিছুটা অনুসন্ধান করার পরে, আমি সিপিপি নমুনায় একটি চিঠি_পরিচয়। ডেটা খুঁজে পেতে পারি। আমি এটি ব্যবহার করেছি এবং সিভি 2 এর জন্য একটি কোড তৈরি করেছি letter লেটার_রেকোগ.পি এর মডেলটিতে নিকটতম (কেবলমাত্র পরীক্ষার জন্য):

import numpy as np
import cv2

fn = 'letter-recognition.data'
a = np.loadtxt(fn, np.float32, delimiter=',', converters={ 0 : lambda ch : ord(ch)-ord('A') })
samples, responses = a[:,1:], a[:,0]

model = cv2.KNearest()
retval = model.train(samples,responses)
retval, results, neigh_resp, dists = model.find_nearest(samples, k = 10)
print results.ravel()

এটি আমাকে 20000 আকারের অ্যারে দিয়েছে, আমি এটি বুঝতে পারি না।

প্রশ্নাবলী:

1) লেটার_সেকগনিশন.ডাটা ফাইল কী? কীভাবে আমার নিজের ডেটা সেট থেকে ফাইলটি তৈরি করবেন?

2) কি results.reval()বোঝায়?

৩) লেটার_সেকগনিশন.ডাটা ফাইল (কেএনরেস্ট বা এসভিএম হয়) ব্যবহার করে আমরা কীভাবে একটি সাধারণ অঙ্কের স্বীকৃতি সরঞ্জাম লিখতে পারি?

উত্তর:


527

ঠিক আছে, উপরের সমস্যা সমাধানের জন্য আমি আমার প্রশ্নে নিজেকে ওয়ার্কআউট করার সিদ্ধান্ত নিয়েছি। আমি যা চেয়েছিলাম তা হল ওপেনসিভিতে কে নেয়ারেস্ট বা এসভিএম বৈশিষ্ট্যগুলি ব্যবহার করে একটি সাধারণ ওসিআর বাস্তবায়ন করা। এবং নীচে আমি কি করেছি এবং কীভাবে তা করছি। (এটি কেবল ওসিআরের সাধারণ উদ্দেশ্যে কী-কেয়ারস্টকে কীভাবে ব্যবহার করতে হয় তা শেখার জন্য)।

1) আমার প্রথম প্রশ্নটি ছিল লেটার_সেকগনিশন.ডাটা ফাইল সম্পর্কে যা ওপেনসিভি নমুনাগুলি নিয়ে আসে। আমি জানতে চেয়েছিলাম যে এই ফাইলটির ভিতরে কী আছে।

এটিতে একটি চিঠি এবং সেই চিঠির 16 টি বৈশিষ্ট্য রয়েছে।

এবং this SOFএটি খুঁজে পেতে আমাকে সহায়তা করেছে। এই 16 বৈশিষ্ট্যগুলি কাগজে ব্যাখ্যা করা হয়েছে Letter Recognition Using Holland-Style Adaptive Classifiers। (যদিও আমি কিছু বৈশিষ্ট্যগুলি শেষ পর্যন্ত বুঝতে পারি নি)

2) যেহেতু আমি জানতাম, এই সমস্ত বৈশিষ্ট্যগুলি না বুঝে, সেই পদ্ধতিটি করা কঠিন। আমি অন্য কিছু কাগজপত্র চেষ্টা করেছিলাম, তবে একটি শিক্ষানবিশের জন্য সমস্ত কিছুটা কঠিন ছিল।

So I just decided to take all the pixel values as my features. (আমি নির্ভুলতা বা পারফরম্যান্স নিয়ে চিন্তিত নই, আমি কেবল এটি কাজ করতে চেয়েছিলাম, কমপক্ষে কমপক্ষে নির্ভুলতার সাথে)

আমি আমার প্রশিক্ষণের ডেটার জন্য চিত্রটি নীচে নিয়েছি:

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

(আমি জানি প্রশিক্ষণের ডেটার পরিমাণ কম But তবে, যেহেতু সমস্ত বর্ণগুলি একই হরফ এবং আকারের, তাই আমি এটি চেষ্টা করার সিদ্ধান্ত নিয়েছিলাম)।

প্রশিক্ষণের জন্য ডেটা প্রস্তুত করতে, আমি ওপেনসিভিতে একটি ছোট কোড তৈরি করেছি। এটি নিম্নলিখিত জিনিসগুলি করে:

  1. এটি চিত্রটি লোড করে।
  2. অঙ্কগুলি নির্বাচন করে (স্পষ্টতই মিথ্যা সনাক্তকরণ এড়াতে অক্ষরের ক্ষেত্র এবং উচ্চতার ক্ষেত্রে সীমাবদ্ধতা সন্ধান এবং প্রয়োগের মাধ্যমে)।
  3. একটি বর্ণের চারদিকে আবদ্ধ আয়তক্ষেত্রটি আঁকুন এবং অপেক্ষা করুন key press manually। এবার আমরা বাক্সের চিঠির সাথে অনুরূপ ডিজিট কীটি টিপব
  4. একবার সম্পর্কিত অঙ্ক কী টিপে গেলে, এটি এই বাক্সটিকে 10x10 এ আকার দেয় এবং 100 টি পিক্সেল মান সংরক্ষণ করে (এখানে, নমুনা) এবং ম্যানুয়ালি অন্য একটি অ্যারে অঙ্কিত অঙ্ক (এখানে প্রতিক্রিয়া))
  5. তারপরে উভয় অ্যারে পৃথক txt ফাইলগুলিতে সংরক্ষণ করুন।

অঙ্কগুলির ম্যানুয়াল শ্রেণিবিন্যাসের শেষে, ট্রেনের সমস্ত অংকের (ট্রেন.পিএনজি) সমস্ত অঙ্কগুলি নিজে নিজে লেবেলযুক্ত হয়, চিত্রটি নীচের মত দেখাবে:

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

উপরের উদ্দেশ্যগুলির জন্য আমি নীচের কোডটি ব্যবহার করেছি (অবশ্যই, এত পরিষ্কার নয়):

import sys

import numpy as np
import cv2

im = cv2.imread('pitrain.png')
im3 = im.copy()

gray = cv2.cvtColor(im,cv2.COLOR_BGR2GRAY)
blur = cv2.GaussianBlur(gray,(5,5),0)
thresh = cv2.adaptiveThreshold(blur,255,1,1,11,2)

#################      Now finding Contours         ###################

contours,hierarchy = cv2.findContours(thresh,cv2.RETR_LIST,cv2.CHAIN_APPROX_SIMPLE)

samples =  np.empty((0,100))
responses = []
keys = [i for i in range(48,58)]

for cnt in contours:
    if cv2.contourArea(cnt)>50:
        [x,y,w,h] = cv2.boundingRect(cnt)

        if  h>28:
            cv2.rectangle(im,(x,y),(x+w,y+h),(0,0,255),2)
            roi = thresh[y:y+h,x:x+w]
            roismall = cv2.resize(roi,(10,10))
            cv2.imshow('norm',im)
            key = cv2.waitKey(0)

            if key == 27:  # (escape to quit)
                sys.exit()
            elif key in keys:
                responses.append(int(chr(key)))
                sample = roismall.reshape((1,100))
                samples = np.append(samples,sample,0)

responses = np.array(responses,np.float32)
responses = responses.reshape((responses.size,1))
print "training complete"

np.savetxt('generalsamples.data',samples)
np.savetxt('generalresponses.data',responses)

এখন আমরা প্রশিক্ষণ এবং পরীক্ষার অংশে প্রবেশ করি।

অংশটি পরীক্ষার জন্য আমি চিত্রের নীচে ব্যবহার করেছি, যার ট্রেনিংয়ের জন্য একই ধরণের অক্ষর রয়েছে।

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

প্রশিক্ষণের জন্য আমরা নিম্নরূপ করি :

  1. আমরা ইতিমধ্যে সংরক্ষিত txt ফাইলগুলি লোড করুন
  2. আমরা যে শ্রেণিবদ্ধের ব্যবহার করছি তার একটি উদাহরণ তৈরি করুন (এখানে, এটি কেএনরেস্ট)
  3. তারপরে আমরা ডেটা প্রশিক্ষণের জন্য KNearest.train ফাংশনটি ব্যবহার করি

পরীক্ষার উদ্দেশ্যে, আমরা নিম্নলিখিত হিসাবে করি:

  1. আমরা পরীক্ষার জন্য ব্যবহৃত চিত্রটি লোড করি
  2. পূর্বের মতো চিত্রটি প্রক্রিয়া করুন এবং কনট্যুর পদ্ধতি ব্যবহার করে প্রতিটি অঙ্কটি বের করুন
  3. এর জন্য সীমানা বাক্স আঁকুন, তারপরে 10x10 এ আকার দিন এবং এর পিক্সেল মানগুলি আগের মতো করে অ্যারেতে সংরক্ষণ করুন।
  4. তারপরে আমরা যেটি দিয়েছি তার নিকটতম আইটেমটি সন্ধান করতে আমরা কেএনরেস্ট.ফাইন্ড_নেস্ট () ফাংশনটি ব্যবহার করি। (ভাগ্যবান হলে, এটি সঠিক সংখ্যাটি স্বীকৃতি দেবে))

আমি নীচে একক কোডে শেষ দুটি পদক্ষেপ (প্রশিক্ষণ এবং পরীক্ষা) অন্তর্ভুক্ত করেছি:

import cv2
import numpy as np

#######   training part    ############### 
samples = np.loadtxt('generalsamples.data',np.float32)
responses = np.loadtxt('generalresponses.data',np.float32)
responses = responses.reshape((responses.size,1))

model = cv2.KNearest()
model.train(samples,responses)

############################# testing part  #########################

im = cv2.imread('pi.png')
out = np.zeros(im.shape,np.uint8)
gray = cv2.cvtColor(im,cv2.COLOR_BGR2GRAY)
thresh = cv2.adaptiveThreshold(gray,255,1,1,11,2)

contours,hierarchy = cv2.findContours(thresh,cv2.RETR_LIST,cv2.CHAIN_APPROX_SIMPLE)

for cnt in contours:
    if cv2.contourArea(cnt)>50:
        [x,y,w,h] = cv2.boundingRect(cnt)
        if  h>28:
            cv2.rectangle(im,(x,y),(x+w,y+h),(0,255,0),2)
            roi = thresh[y:y+h,x:x+w]
            roismall = cv2.resize(roi,(10,10))
            roismall = roismall.reshape((1,100))
            roismall = np.float32(roismall)
            retval, results, neigh_resp, dists = model.find_nearest(roismall, k = 1)
            string = str(int((results[0][0])))
            cv2.putText(out,string,(x,y+h),0,1,(0,255,0))

cv2.imshow('im',im)
cv2.imshow('out',out)
cv2.waitKey(0)

এবং এটি কাজ করেছে, নীচে আমি পেয়েছি ফলাফল:

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


এখানে এটি 100% নির্ভুলতার সাথে কাজ করেছে। আমি ধরে নিলাম এটি কারণ সমস্ত অঙ্কগুলি একই ধরণের এবং একই আকারের।

তবে যে কোনও উপায়ে, এটি নতুনদের জন্য যাওয়ার জন্য একটি ভাল শুরু (আমি আশা করি))


67
+1 দীর্ঘ পোস্ট, তবে খুব শিক্ষামূলক। এটি ওপেনসিভি ট্যাগ তথ্যতে
করলফিলিপ

12
কারও আগ্রহী হওয়ার ক্ষেত্রে, আমি কিছু ঘন্টা এবং সিঁড়ি সহ এই কোড থেকে একটি উপযুক্ত ওও ইঞ্জিন তৈরি করেছি: github.com/goncalopp/simple-ocr-opencv
goncalopp

10
মনে রাখবেন যে আপনার যখন একটি ভাল সংজ্ঞায়িত নিখুঁত ফন্ট রয়েছে তখন এসভিএম এবং কেএনএন ব্যবহার করার দরকার নেই। উদাহরণস্বরূপ, 0, 4, 6, 9 সংখ্যাগুলি একটি গোষ্ঠী গঠন করে, 1, 2, 3, 5, 7 অঙ্কগুলি অন্যটি এবং 8 টিতে রূপ দেয়। এই গ্রুপটি ইউলার নাম্বার দ্বারা দেওয়া হয়েছে। তারপরে "0" এর কোনও শেষ পয়েন্ট নেই, "4" এর দুটি আছে, এবং "6" এবং "9" সেন্ট্রয়েড অবস্থান দ্বারা পৃথক করা হয়। অন্যান্য গ্রুপে "3" একমাত্র 3 টি সমাপ্তি রয়েছে। "1" এবং "7" কঙ্কালের দৈর্ঘ্যের দ্বারা পৃথক করা হয়। অঙ্কের সাথে একত্রে উত্তল হালকে বিবেচনা করার সময়, "5" এবং "2" এর দুটি গর্ত থাকে এবং এগুলি বৃহত্তম গর্তের সেন্ট্রয়েড দ্বারা পৃথক করা যায়।
মিমজিপি

4
সমস্যা আছে .. ধন্যবাদ। এটি একটি দুর্দান্ত টিউটোরিয়াল ছিল। আমি একটি ছোট ভুল ছিল। আমার এবং @ আর্যাশের মতো আর কেউ যদি একই সমস্যার মুখোমুখি হন তবে এটি কারণ আপনি ভুল কী টিপছেন। বাক্সে প্রতিটি সংখ্যার জন্য আপনাকে এটিকে প্রবেশ করতে হবে যাতে এটি এতে প্রশিক্ষিত হয়। আশা করি এইটি কাজ করবে.
শালকি

19
একটি দুর্দান্ত টিউটোরিয়াল। ধন্যবাদ! ওপেনসিভির সর্বশেষ (৩.১) ভার্সনটির সাথে কাজ করার জন্য এখানে কয়েকটি পরিবর্তন দরকার: সংক্ষেপগুলি, স্তরক্রম = cv2.findContours (ত্রিশ, cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE) => _, কনট্যুরস, ক্রমবর্ধমান = cv2.findContours (ত্রিশ, cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE), মডেল = cv2.KNarerest () => মডেল = cv2.ML.K নিকটবর্তী_ক্রিয়েট (), মডেল.ট্রেইন (নমুনা, প্রতিক্রিয়া) => মডেল.ট্রেইন (নমুনা, cv2.ML) .ROW_SAMPLE, প্রতিক্রিয়া), প্রতিক্রিয়া, ফলাফল, হিং_স্রষ্টা, বিঘ্ন = মডেল.ফাইন্ড_নিস্ট (রোসমেল, কে = 1) => প্রত্যাহার, ফলাফল, হিং_নস্পেস, ডিসটস = মডেল.ফাইন্ড_নিস্ট (রোসমেল, কে = 1)
জোহানেস ব্রডওয়াল

53

যারা সি ++ কোডে আগ্রহী তাদের নীচের কোডটি উল্লেখ করতে পারেন। ধন্যবাদ আবিদ রহমান সুন্দর ব্যাখ্যার জন্য।


পদ্ধতিটি উপরের মতো একই তবে, কনট্যুর সন্ধানটি কেবল প্রথম স্তরের স্তরের স্তরের কনট্যুর ব্যবহার করে, যাতে অ্যালগোরিদম প্রতিটি অঙ্কের জন্য কেবলমাত্র বাইরের কনট্যুর ব্যবহার করে।

নমুনা এবং লেবেল ডেটা তৈরির জন্য কোড

//Process image to extract contour
Mat thr,gray,con;
Mat src=imread("digit.png",1);
cvtColor(src,gray,CV_BGR2GRAY);
threshold(gray,thr,200,255,THRESH_BINARY_INV); //Threshold to find contour
thr.copyTo(con);

// Create sample and label data
vector< vector <Point> > contours; // Vector for storing contour
vector< Vec4i > hierarchy;
Mat sample;
Mat response_array;  
findContours( con, contours, hierarchy,CV_RETR_CCOMP, CV_CHAIN_APPROX_SIMPLE ); //Find contour

for( int i = 0; i< contours.size(); i=hierarchy[i][0] ) // iterate through first hierarchy level contours
{
    Rect r= boundingRect(contours[i]); //Find bounding rect for each contour
    rectangle(src,Point(r.x,r.y), Point(r.x+r.width,r.y+r.height), Scalar(0,0,255),2,8,0);
    Mat ROI = thr(r); //Crop the image
    Mat tmp1, tmp2;
    resize(ROI,tmp1, Size(10,10), 0,0,INTER_LINEAR ); //resize to 10X10
    tmp1.convertTo(tmp2,CV_32FC1); //convert to float
    sample.push_back(tmp2.reshape(1,1)); // Store  sample data
    imshow("src",src);
    int c=waitKey(0); // Read corresponding label for contour from keyoard
    c-=0x30;     // Convert ascii to intiger value
    response_array.push_back(c); // Store label to a mat
    rectangle(src,Point(r.x,r.y), Point(r.x+r.width,r.y+r.height), Scalar(0,255,0),2,8,0);    
}

// Store the data to file
Mat response,tmp;
tmp=response_array.reshape(1,1); //make continuous
tmp.convertTo(response,CV_32FC1); // Convert  to float

FileStorage Data("TrainingData.yml",FileStorage::WRITE); // Store the sample data in a file
Data << "data" << sample;
Data.release();

FileStorage Label("LabelData.yml",FileStorage::WRITE); // Store the label data in a file
Label << "label" << response;
Label.release();
cout<<"Training and Label data created successfully....!! "<<endl;

imshow("src",src);
waitKey();

প্রশিক্ষণ এবং পরীক্ষার জন্য কোড

Mat thr,gray,con;
Mat src=imread("dig.png",1);
cvtColor(src,gray,CV_BGR2GRAY);
threshold(gray,thr,200,255,THRESH_BINARY_INV); // Threshold to create input
thr.copyTo(con);


// Read stored sample and label for training
Mat sample;
Mat response,tmp;
FileStorage Data("TrainingData.yml",FileStorage::READ); // Read traing data to a Mat
Data["data"] >> sample;
Data.release();

FileStorage Label("LabelData.yml",FileStorage::READ); // Read label data to a Mat
Label["label"] >> response;
Label.release();


KNearest knn;
knn.train(sample,response); // Train with sample and responses
cout<<"Training compleated.....!!"<<endl;

vector< vector <Point> > contours; // Vector for storing contour
vector< Vec4i > hierarchy;

//Create input sample by contour finding and cropping
findContours( con, contours, hierarchy,CV_RETR_CCOMP, CV_CHAIN_APPROX_SIMPLE );
Mat dst(src.rows,src.cols,CV_8UC3,Scalar::all(0));

for( int i = 0; i< contours.size(); i=hierarchy[i][0] ) // iterate through each contour for first hierarchy level .
{
    Rect r= boundingRect(contours[i]);
    Mat ROI = thr(r);
    Mat tmp1, tmp2;
    resize(ROI,tmp1, Size(10,10), 0,0,INTER_LINEAR );
    tmp1.convertTo(tmp2,CV_32FC1);
    float p=knn.find_nearest(tmp2.reshape(1,1), 1);
    char name[4];
    sprintf(name,"%d",(int)p);
    putText( dst,name,Point(r.x,r.y+r.height) ,0,1, Scalar(0, 255, 0), 2, 8 );
}

imshow("src",src);
imshow("dst",dst);
imwrite("dest.jpg",dst);
waitKey();

ফলাফল

ফলস্বরূপ প্রথম লাইনের বিন্দুটি 8 হিসাবে চিহ্নিত হয়েছে এবং আমরা বিন্দুর জন্য প্রশিক্ষণ পাইনি। এছাড়াও আমি প্রথম স্তরের স্তরের প্রতিটি কনট্যুরকে নমুনা ইনপুট হিসাবে বিবেচনা করছি, ব্যবহারকারী অঞ্চলটি গণনা করে এড়াতে পারবেন।

ফলাফল


1
আমি এই কোডটি চালাতে ক্লান্ত হয়ে পড়েছি। আমি নমুনা এবং লেবেল ডেটা তৈরি করতে সক্ষম হয়েছি। তবে আমি যখন পরীক্ষা-প্রশিক্ষণ ফাইলটি চালাচ্ছি তখন এটি একটি ত্রুটি নিয়ে চলে *** stack smashing detected ***:এবং তাই আপনি উপরে উঠার সাথে আমি চূড়ান্ত যথাযথ চিত্র পাচ্ছি না (সবুজ বর্ণের অঙ্কগুলি)
স্কেমে

1
আমি char name[4];আপনার কোডটিতে পরিবর্তিত char name[7];হয়েছি এবং স্ট্যাক সম্পর্কিত ত্রুটিটি পাই নি তবে এখনও আমি সঠিক ফলাফল পাচ্ছি না। আমি এখানে মত একটি ইমেজ পাচ্ছি < i.imgur.com/qRkV2B4.jpg >
skm

@ এসএসএম এটি নিশ্চিত করুন যে আপনি ছবিতে অঙ্কের সংখ্যার সমতুল্য কনট্যুর পেয়ে যাচ্ছেন, কনসোলে ফলাফল মুদ্রণ করেও চেষ্টা করুন।
হারিস

1
হ্যালো, আমরা কি প্রশিক্ষণের জন্য নেট ব্যবহার করতে পারি?
ইয়োডে

14

আপনি যদি মেশিন লার্নিংয়ে শিল্পের স্থিতিতে আগ্রহী হন তবে আপনার ডিপ লার্নিংয়ের দিকে নজর দেওয়া উচিত। আপনার জিপিইউ সমর্থনকারী একটি সিইডিএ থাকা উচিত বা বিকল্পভাবে অ্যামাজন ওয়েব পরিষেবাদিতে জিপিইউ ব্যবহার করুন।

টেনসর ফ্লো ব্যবহার করে গুগল উদাসিটির একটি দুর্দান্ত টিউটোরিয়াল রয়েছে । এই টিউটোরিয়ালটি আপনাকে শিখিয়ে দেবে কীভাবে হাতের লিখিত অঙ্কগুলিতে নিজের শ্রেণিবদ্ধকে প্রশিক্ষণ দেওয়া যায়। কনভলিউশনাল নেটওয়ার্ক ব্যবহার করে পরীক্ষার সেটটিতে আমি 97% এরও বেশি নির্ভুলতা পেয়েছি।

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.