答題卡圖像識別
創(chuàng)新互聯(lián)是一家集網(wǎng)站建設(shè),坡頭企業(yè)網(wǎng)站建設(shè),坡頭品牌網(wǎng)站建設(shè),網(wǎng)站定制,坡頭網(wǎng)站建設(shè)報價,網(wǎng)絡(luò)營銷,網(wǎng)絡(luò)優(yōu)化,坡頭網(wǎng)站推廣為一體的創(chuàng)新建站企業(yè),幫助傳統(tǒng)企業(yè)提升企業(yè)形象加強企業(yè)競爭力??沙浞譂M足這一群體相比中小企業(yè)更為豐富、高端、多元的互聯(lián)網(wǎng)需求。同時我們時刻保持專業(yè)、時尚、前沿,時刻以成就客戶成長自我,堅持不斷學(xué)習(xí)、思考、沉淀、凈化自己,讓我們?yōu)楦嗟钠髽I(yè)打造出實用型網(wǎng)站。需求分析、市場分析和技術(shù)實現(xiàn)
一、需求分析
一、以接口的方式開發(fā)此需求:
1:接收圖片
以上傳的方式把圖片發(fā)送到接口。
2:識別圖片
接口接收到圖片后,進行圖像識別。
3:返回數(shù)據(jù)
返回識別后的JSON格式數(shù)據(jù)。
二、答題卡圖片識別的具體要求:
圖片是通過手機、相機、掃描儀等設(shè)備拍照而來,其中手機、相機拍出的照片會出現(xiàn)像素低、圖像不正、聚焦不清楚等問題;
1:圖片只要是人眼能看清楚的即可完成識別;
2:800萬像素以上的手機拍的照片能進行識別;
3:聚焦不清楚時也可以進行識別;
4:不符合要求的圖片可以不識別,一旦識別,正確率必須保證100%。
三、其他要求:
1:此項目驗收需要提供答題卡識別的所有源代碼、接口說明文檔。
2:接口需支持單張圖片上傳識別以及多張圖片的上傳識別。
3:接口使用的開發(fā)語言及開發(fā)工具不限。
四、需求分析:
這是一個典型的“機器視覺”應(yīng)用。其中,答題卡的樣式可以是由自己來設(shè)置的,圖片的獲取方式提到了可以是“手機拍照、相機拍照”這種比較方便的方式;本例的一個特殊的要求是:你可以識別不出來,但是你不能識別錯誤,這是項目的特殊要求
五、需求分析:
普通的答題卡是這樣的:
用于機器識別的答題卡是這樣的,最明顯的區(qū)別在于在邊界處提供了用于標定的黑邊。由于這里的答題卡是可以自己來設(shè)計的,就應(yīng)該設(shè)計得最適合識別:
經(jīng)過我修改的答題卡是這樣的,主要是用圓點進行邊界標定,因為在旋轉(zhuǎn)和縮放的情況下,圓點都有更好的性能:
二、市場分析
答題卡已經(jīng)出現(xiàn)好多年了,而且教育機構(gòu)也是容易出現(xiàn)壁壘的領(lǐng)域。經(jīng)過簡單調(diào)查,制式的答題機應(yīng)該是這種樣子的,這種答題機采用的應(yīng)該特殊的成像技術(shù),比如紅外之類的,否則也不需要做成這種樣子:
其價格在數(shù)千元到萬元左右,淘寶上也有人做出了機器識別的例子:
采用普通攝像頭和特定的支架,銷售情況不好。
但是,圖像確是多種多樣的。
形式多樣。值得關(guān)注的一點是,這些能夠通過baidu直接搜索得到的答題卡在設(shè)計上和本文提供的答題開有兩點比較大的不同,一個是在取消了比如圓點這樣的標定點,二個是在橫版面上采用了“點畫”的方式進行標定
這樣能夠得到的結(jié)果還是使得答題卡更加的簡潔,美觀。
對于這個市場,我認為在網(wǎng)絡(luò)和即時聊天工具更加發(fā)達的今天,答題卡作為一種非常正式的考試方法,還是有其市場的(比如高考中考,短時間內(nèi)還不會出現(xiàn)直接采用移動設(shè)備進行答卷);但是專門去做一套這樣的設(shè)備,市場已經(jīng)基本飽和,而且教育市場的壁壘應(yīng)該很高,不是很容易就能夠進入的。但是,對于在日常非正式考試中需要答題卡相關(guān)設(shè)備,而不希望擔(dān)負一套昂貴的專業(yè)系統(tǒng)的人或單位來所,如果能夠以一種比較低廉的價格,并且已一種比較方便操作的方式(比如直接利用手機,或普通相機)進行實現(xiàn),應(yīng)該是有一定的市場的。
三、技術(shù)實現(xiàn)
本例的技術(shù)難度不是很大,非常關(guān)鍵的一點是由于卡片是可以由自己來設(shè)計的。而且圖像的獲取也比較容易被優(yōu)化。這里以最前面的圖片進行設(shè)計分析,其他的例子情況可以以此類推;并且公布核心代碼。
1)仿照實際的情況,對原始圖片進行相關(guān)處理。在實際拍攝的時候,可能會出現(xiàn)“縮放”、“透視變化”等影響最終實際結(jié)果的情況:
變小
透視變化
同時透視和縮放
2)編寫獲取錨點(就是圓點)的函數(shù). FetchAnchorPoints函數(shù)的主要過程是將輸入的圖片劃分為四個部分,并且分別找到其中的圓點。參數(shù)中mattmp是模板圖片,也就是哪個小圓的圖片。
//獲得錨點
void FetchAnchorPoints(Mat src,Mat mattmp,Point &anchor01,Point &anchor02,Point &anchor03,Point &anchor04)
{
Mat p_w_picpathmatch;
Point minLoc;
Point maxLoc01,maxLoc02,maxLoc03,maxLoc04;
//Point anchor01,anchor02,anchor03,anchor04;
double minVal;
double maxVal2;
//Mat src = imread("C:/answercard/1.jpg",0);//讀入黑白原始圖像
int srcRows = src.rows;
int srcCols = src.cols;
Mat src01 = src(Rect(0,0,srcCols/2,srcRows/2));
Mat src02 = src(Rect(srcCols/2,0,srcCols/2,srcRows/2));
Mat src03 = src(Rect(0,srcRows/2,srcCols/2,srcRows/2));
Mat src04 = src(Rect(srcCols/2,srcRows/2,srcCols/2,srcRows/2));
//imshow("src01",src01);imshow("src02",src02);imshow("src03",src03);imshow("src04",src04);
matchTemplate( mattmp, src01, p_w_picpathmatch, 5 );
normalize( p_w_picpathmatch, p_w_picpathmatch, 0, 1, NORM_MINMAX, -1, Mat() );
minMaxLoc( p_w_picpathmatch, &minVal, &maxVal2, &minLoc, &maxLoc01, Mat() );
anchor01 = maxLoc01;
//circle(src,maxLoc01,3,Scalar(0),3);
matchTemplate( mattmp, src02, p_w_picpathmatch, 5 );
normalize( p_w_picpathmatch, p_w_picpathmatch, 0, 1, NORM_MINMAX, -1, Mat() );
minMaxLoc( p_w_picpathmatch, &minVal, &maxVal2, &minLoc, &maxLoc02, Mat() );
anchor02 = Point(maxLoc02.x+srcCols/2,maxLoc02.y);
//circle(src,anchor02,3,Scalar(0),3);
matchTemplate( mattmp, src03, p_w_picpathmatch, 5 );
normalize( p_w_picpathmatch, p_w_picpathmatch, 0, 1, NORM_MINMAX, -1, Mat() );
minMaxLoc( p_w_picpathmatch, &minVal, &maxVal2, &minLoc, &maxLoc03, Mat() );
anchor03 = Point(maxLoc03.x,maxLoc03.y+srcRows/2);
//circle(src,anchor03,3,Scalar(0),3);
matchTemplate( mattmp, src04, p_w_picpathmatch, 5 );
normalize( p_w_picpathmatch, p_w_picpathmatch, 0, 1, NORM_MINMAX, -1, Mat() );
minMaxLoc( p_w_picpathmatch, &minVal, &maxVal2, &minLoc, &maxLoc04, Mat() );
anchor04 = Point(maxLoc04.x+srcCols/2,maxLoc04.y+srcRows/2);
//circle(src,anchor04,3,Scalar(0),3);
}
獲得的結(jié)果
3)采用warpPerspective進行透視變換,如果對warpPerspective不是很了解可以查看我前面的blog
Point anchor01,anchor02,anchor03,anchor04; Point2f src_vertices[4];
Point2f dst_vertices[4];
//獲得矯正結(jié)果圖像的參數(shù)
Mat matstandard = imread("C:/answercard/1.jpg",0);//讀入黑白原始圖像
Mat mattmp = imread("C:/answercard/temp.jpg",0);
FetchAnchorPoints(matstandard,mattmp,anchor01,anchor02,anchor03,anchor04);
std::cout<<"anchor01"<<anchor01<<" "<<"anchor02"<<anchor02<<" "<<"anchor03"<<anchor03<<" "<<"anchor04"<<anchor04;
dst_vertices[0] = anchor01;
dst_vertices[1] = anchor02;
dst_vertices[2] = anchor03;
dst_vertices[3] = anchor04;
//dst_vertices.push_back(anchor01);dst_vertices.push_back(anchor02);dst_vertices.push_back(anchor03);dst_vertices.push_back(anchor04);
//獲得需要矯正圖像參數(shù)
Mat matsrc = imread("C:/answercard/bigroatate.jpg",0);
FetchAnchorPoints(matsrc,mattmp,anchor01,anchor02,anchor03,anchor04);
cout<<"\n";
std::cout<<"anchor01"<<anchor01<<" "<<"anchor02"<<anchor02<<" "<<"anchor03"<<anchor03<<" "<<"anchor04"<<anchor04;
src_vertices[0] = anchor01;
src_vertices[1] = anchor02;
src_vertices[2] = anchor03;
src_vertices[3] = anchor04;
//src_vertices.push_back(anchor01);src_vertices.push_back(anchor02);src_vertices.push_back(anchor03);src_vertices.push_back(anchor04);
//透視變化
Mat warpMatrix = getPerspectiveTransform(src_vertices, dst_vertices);
cv::Mat rotated;
warpPerspective(matsrc, rotated, warpMatrix, rotated.size(), INTER_LINEAR, BORDER_CONSTANT);
imshow("rotated",rotated);
imshow("matstandard",matstandard);這一步得到的校正圖像:4)對原始圖像進行裁剪//對原始圖像進行裁剪
Mat roi01;Mat roi02;Mat roi03;Mat roi04; anchor01 =dst_vertices[0] ;
anchor02 =dst_vertices[1] ;
anchor03 =dst_vertices[2] ;
anchor04 =dst_vertices[3] ;
//TODO這個地方最終的時候需要改成rotated
roi01 = matstandard(Rect(anchor01.x,anchor01.y+mattmp.rows,20,anchor03.y-anchor01.y-mattmp.rows));
roi02 = matstandard(Rect(anchor01.x+mattmp.cols,anchor01.y,anchor02.x-anchor01.x-mattmp.cols,20));
roi03 = matstandard(Rect(anchor02.x+8,anchor02.y+mattmp.rows,17,anchor04.y-anchor02.y-mattmp.rows));
roi04 = matstandard(Rect(anchor03.x+mattmp.cols,anchor03.y+5,anchor04.x-anchor03.x-mattmp.cols,13));
//roi02 = FetchMaxContour(roi02);
//imshow("roi01",roi01);
//imshow("roi02",roi02);
//imshow("roi03",roi03);
//imshow("roi04",roi04);這一步得到的結(jié)果 5)獲得區(qū)域的投影。這里的操作其實就是獲得圖像的波峰,這樣就能進行定位。//函數(shù)名稱:FetchMaxContour
//函數(shù)作用: 對區(qū)域進行預(yù)處理,返回大的連續(xù)區(qū)域
//參 數(shù): src [in] 輸入mat
//返 回:投影值
vector<int> FetchMaxContour(Mat src)
{
//讀取圖像
Mat testmat = src.clone();
Mat testclone = src.clone();
Mat matcanny;
//用于尋找輪廓
Mat threshold_output;
vector<vector<Point> > contours;
vector<Vec4i> hierarchy;
int imax = 0;int maxsize = 0;
RotatedRect theMinRect;
RotatedRect theMinEllipse;
//imshow("原始圖像",testmat);
//大津法找到敏感區(qū)域
threshold(testmat,testmat,0,255,cv::THRESH_OTSU);
//imshow("大津法",testmat);
//為什么要轉(zhuǎn)換,因為白色是有數(shù)據(jù)的區(qū)域,輪廓是圍繞白色區(qū)域的
threshold(testmat,testmat,0,255,THRESH_BINARY_INV);
imshow("二值",testmat);
//計算縱向投影
vector<int> vcol;itmp = 0;
for (int i=0;i<testmat.cols;i++)
{
for (int j=0;j<testmat.rows;j++)
{
if (testmat.at<uchar>(j,i))
{
itmp = itmp +1;
}
}
vcol.push_back(itmp);
itmp = 0;
}
////對得到的結(jié)果進行處理,計算波峰
//int isum = 0;//一共多少個波峰
vector<int> vrise;
for (int i=1;i<vcol.size();i++)
{
if (vcol[i-1]==0 && vcol[i]>0)
{
vrise.push_back(i);
//isum = isum+1;
}
}
return vrise;
} 6)獲得投影區(qū)域,并且標注出來 vector<int> vroi02 = FetchMaxContour(roi02); vector<Mat> vmat02;
for (int i=1;i<vroi02.size();i++)
{
Mat roi = rotated(Rect(mattmp.cols+anchor01.x+vroi02[i],roi02.rows+38,11,92));
//imshow("roi",roi);
vmat02.push_back(roi);
circle(rotated,Point(mattmp.cols+anchor01.x+vroi02[i],roi02.rows+38),1,Scalar(0),1);
}
vector<int> vroi04 = FetchMaxContour(roi04);
vector<Mat> vmat04;
for (int i=0;i<vroi04.size();i++)
{
Mat roi = rotated(Rect(mattmp.cols+anchor03.x+vroi04[i],153,11,198));
//imshow("roi",roi);
//vmat02.push_back(roi);
circle(rotated,Point(mattmp.rows+anchor03.x+vroi04[i],153),1,Scalar(0),1);
}
imshow("rotated",rotated); 找到的結(jié)果用圓點標注出來這里下面一排第一個圓點沒找到,這是原始模板圖像在設(shè)計的時候出現(xiàn)的問題,因為這里只是說明原理,我就沒有修改。7)架設(shè)照相機,獲取實際圖片做到這一步,下面就是要獲得實際的圖片并進行識別了。我采用的方法是將答題卡用打印機打印出來,然后用相機拍攝下來,注意一下光照,效果如下:照片還是比較模糊的,識別后達到預(yù)期效果。注意模板識別之前首先需要把圖片縮放一下,否則效果不會太好。Mat matsrc = imread("C:/answercard/r4.jpg",0);
resize(matsrc,matsrc,Size(600,500));
FetchAnchorPoints(matsrc,mattmp,anchor01,anchor02,anchor03,anchor04);
效果如此。采用2b鉛筆進行填卡,效果如下進行閾值分析后,效果很差可以發(fā)現(xiàn),采用2b鉛筆,如果采用圖像識別的方法的話,光照的影響還是非常大的。接著改用黑色鉛筆(鋼筆也可以)則特征明顯8)對獲取的結(jié)果進行計算。也就是圖片到數(shù)據(jù)的一個量化的過程。具體來說,就是將這樣的圖像量化成為選擇結(jié)果,思路也是非常直接的,就是對比最右側(cè)的標尺值和實際獲得的值。在編寫具體代碼的時候,可能還要加上一定的修正,并且要盡可能保證這個修正是魯棒的。
vector<int> vroi02 = FetchMaxContour(roi02);
vector<Mat> vmat02;
vector<int> vroi03 = FetchMaxContour(roi03,1);
//減去偏移,這里的偏移量可以從roi03第一個值得出
for (int i=0;i<vroi03.size();i++)
{
vroi03[i] = vroi03[i]-30;
}
int resulttmp = 9;
cout<<"vroi02"<<endl;
//這里i = 0的數(shù)據(jù)是無用數(shù)據(jù)
for (int i=1;i<vroi02.size();i++)
{
Mat roi = rotated(Rect(mattmp.cols+anchor01.x+vroi02[i],roi02.rows+38,11,92));
//vmat02.push_back(roi);
vector<int> vtmp = FetchMaxContour(roi,1);
vtmp[0] = vtmp[0]+4;
for (int k = 0;k<9;k++)
{
if (vtmp[0]>=vroi03[k] && vtmp[0]<vroi03[k+1])
{
resulttmp = k;
break;
}
}
cout<<i<<" is "<<resulttmp<<" | ";
cout<<endl;resulttmp = 9;
if (IsDebug)
{
char* tmp = new char[100];
sprintf(tmp,"C:/answercard/vmat02/%d.jpg",i);
imwrite(tmp,roi);
circle(rotated,Point(mattmp.cols+anchor01.x+vroi02[i],roi02.rows+38),1,Scalar(0),1);
}
} 結(jié)果完全正確:1 is 0 |2 is 1 |3 is 2 |4 is 4 |5 is 3 |6 is 4 |7 is 4 |8 is 5 |9 is 4 |10 is 4 |11 is 5 |12 is 6 |13 is 3 |
四、小結(jié) 答題卡這種東西很早之前就有了,我想在它第一次被提出的時候,絕對是創(chuàng)造性的、革命的東西,大大地提高了考試的生產(chǎn)率。但是之前的那種設(shè)備采用的原理比較精密和復(fù)雜,非常依賴設(shè)備,一定程度上限制了傳播和發(fā)展。今天,隨著機器視覺算法的不斷發(fā)展、移動通信設(shè)備的不斷發(fā)展,解決這種問題有了新的思路和新的市場空間。這也從另一個方向上說明了機器視覺技術(shù)的廣闊前景。 本文從需求分析、市場分析和技術(shù)實現(xiàn)3個方面嘗試對這個問題進行剖析。受制于資源和個人能力,很多地方解釋的不是很清楚,最終開發(fā)出來的代碼雖然具備了一定的解決問題的能力,但是畢竟不夠魯棒和高效。畢竟機器視覺的項目是由市場和實際需求驅(qū)動的,如果有好的想法和需求,歡迎交流。 感謝閱讀,希望有所幫助。
另外有需要云服務(wù)器可以了解下創(chuàng)新互聯(lián)scvps.cn,海內(nèi)外云服務(wù)器15元起步,三天無理由+7*72小時售后在線,公司持有idc許可證,提供“云服務(wù)器、裸金屬服務(wù)器、高防服務(wù)器、香港服務(wù)器、美國服務(wù)器、虛擬主機、免備案服務(wù)器”等云主機租用服務(wù)以及企業(yè)上云的綜合解決方案,具有“安全穩(wěn)定、簡單易用、服務(wù)可用性高、性價比高”等特點與優(yōu)勢,專為企業(yè)上云打造定制,能夠滿足用戶豐富、多元化的應(yīng)用場景需求。
新聞標題:答題卡圖像識別需求分析、市場分析和技術(shù)實現(xiàn)-創(chuàng)新互聯(lián)
本文URL:http://jinyejixie.com/article44/dcjshe.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供域名注冊、商城網(wǎng)站、App開發(fā)、網(wǎng)站排名、外貿(mào)網(wǎng)站建設(shè)、企業(yè)網(wǎng)站制作
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)
猜你還喜歡下面的內(nèi)容