OpenCV -ն Բաց կոդով մեքենայական տեսողության գրադարան է, որը պարունակում է մեքենայական տեսողության, պատկերների մշակման և թվային մեթոդների ավելի քան 500 ֆունկցիաներ։ Գրադարանը գրված է C/C++ լեզվով և ակտիվ մշակման փուլում է գտնվում python, java, ruby, Matlab, Lua լեզուների համար տարբերակները։ Գրադարանը կարող է ազատորեն կիրառվել ակադեմիական և կոմերցիոն նպատակների համար և տարածվում է BSD լիցենզիայի պայմաններով։ Ներկայումս հասանելի են Windows, Linux և Mac օպերացիոն համակարգերի համար նախատեսված տարբերակները։ Գրադարանը կարող էք բեռնել արտադրողի կայքից: Բեռնեք գրադարանի վերջին տարբերակը՝ համապատասխան օպերացիոն համակարգի համար, որի վրա աշխատելու էք։ Opencv գրադարանը լրացուցիչ արագացում է ստանում intel միկրոպրոցեսորներով պլատֆորմների վրա շնորհիվ intel® Image Processing Library (IPL ազդանշանների, պատկերների, մեդիա կոդեկների մշակման ցածր մակարդակի գրադարան) գրադարանի։ Opencv -ն ավտոմատ կարողանում է հայտնաբերել IPL գրադարանի առկայությունը։ IPL -ը վճարովի է։
OpenCv գրադարանը բաղկացած է հետևյալ բաղկացուցիչ մասերից CXCORE, CV, ML, HIGHGUI, CVCAM, CVAUX մոդուլներից։
CXCORE – միջուկը բաղկացած է
– բազային հանգույցներ,
– մատրիցների հանրահաշիվ,
– հիշողության հետ աշխատանքի ալգորիթմներ,
– տիպերի ձևափոխության ալգորիթմներ,
– սխալների մշակման ալգորիթմներ,
– XML ֆայլերում գրել/կարդալու ալգորիթմներ,
– 2D գրաֆիկների հետ աշխատելու ալգորիթմներ։
CV – պատկերների մշակման, մեքենայական տեսողության մոդուլը պարունակում է․
– պատկերների հետ աշխատանքի ֆունկցիաներ․ ձևափոխություններ, զտումներ և այլն,
– պատկերների վերլուծության ֆունկցիաներ․ կոնտուրների փնտրում, հիստոգրամներ և այլն,
– շարժումների վերլուծության ալգորիթմներ, օբյեկտների տեղաշարժումների հետևում,
– օբյեկտների ճանաչման ալգորիթմներ․ մարդկանց դեմքերի, առարկաների և այլն,
– տեսախցիկների ստուգաճշտման ալգորիթմներ։
ML– սա չեմ կարող թարգմանել Machine Learning (մեքենայական կրթություն կամ մեքենայական սովորում չի լինում էլի 😉 ):
HIGHGUI – օգտագործողի ինտերֆեյսի ստեղծման մոդուլը բաղկացած է՝
– պատուհանների ստեղծում,
– պատկերների արտածում,
– վիդոեպատկերների զավթում (video capture) տեսախցիկներից և ֆայլերից,
– պատկերների կարդալ/գրել։
CVCAM – թվային տեսախցիկներից վիդեոպատկերների զավթում (video capture)։
CVAUX – ֆուկնցիաներ են, որոնք նախատեսված են․
– տարածական տեսողության,
– դիմագծերի փնտրման և նկարագրման,
– ստերեո համապատասխանությունների փնտրման,
– հյուսվածքների (texture) նկարագրություն:
OpenCv գրադարանը կարող է աշխատել հետևյալ կոմպիլյատորների հետ․
– Windows – Microsoft Visual C++, Borland C++, Intel Compiler, MinGW,
– Linux – GCC, Intel Compiler,
– Mac – Intel Compiler, Carbon և այլ։
Վերջացնելով OpenCv գրադարանի համառոտ նկարագրությունը՝ անցնենք նրա տեղակայմանը Linux օպերացիոն համակարգում։
Դրա համար հաջորդաբար կատարում ենք ստորև բերված հրամանները․
1. Թարմացնում ենք օպերացիոն համակարգում եղած ծրագրային փաթեթները և ծրագրերը․
1.1 sudo apt-get update 1.2 sudo apt-get upgrade
2. Հետևյալ հրամանով տեղակայում ենք հետևյալ ծրագրերը․
sudo apt-get install build-essential libgtk2.0-dev libjpeg-dev libtiff4-dev libjasper-dev libopenexr-dev cmake python-dev python-numpy python-tk libtbb-dev libeigen2-dev yasm libfaac-dev libopencore-amrnb-dev libopencore-amrwb-dev libtheora-dev libvorbis-dev libxvidcore-dev libx264-dev libqt4-dev libqt4-opengl-dev sphinx-common texlive-latex-extra libv4l-dev libdc1394-22-dev libavcodec-dev libavformat-dev libswscale-dev
3. Նյութի սկզբում բերված հղումով քաշում և ապարխիվացնում ենք OpenCV գրադարանը, իմ մոտ 2.4.0 տարբերակն է, դուք կարող էք կրկնել նույնը՝ փոխելով միայն OpenCV-2.4.0 ձեր տարբերակի անունով․
tar -xvf OpenCV-2.4.0.tar.bz2 cd OpenCV-2.4.0/ mkdir build cd build
4. Կոնֆիգուրացնում և նախնական կարգաբերումներ ենք տալիս տեղակայումից առաջ․
cmake -D WITH_TBB=ON -D BUILD_NEW_PYTHON_SUPPORT=ON -D WITH_V4L=ON -D INSTALL_C_EXAMPLES=ON -D INSTALL_PYTHON_EXAMPLES=ON -D BUILD_EXAMPLES=ON -D WITH_QT=ON -D WITH_OPENGL=ON ..
5. Կոմպիլացնում ենք գրադարանի կոդը
make
6. Տեղակայում ենք գրադարանը
sudo make install
7. Որպեսզի մեր ծրագիրը կատարման ժամանակ հղվի OpenCV գրադարանի վրա պետք է կոնֆիգուրացնել /etc/ld.so.conf ֆայլը․
sudo vim /etc/ld.so.conf.d/opencv.conf
Եվ բացված ֆայլում ավելացնում ենք հետևյալ տողը․
/usr/local/lib
Եթե vim տեքստային խմբագրիչը չկա ձեր համակարգչում կարող էք դրա փոխարեն օգտագործել ցանկացած ուրիշը՝ օրինակ gedit -ը։
7. Տերմինալի մեջ գրում ենք
sudo ldconfig
8. Բացում ենք bash.bashrc ֆայլը
sudo gedit /etc/bash.bashrc
և որևէ ազատ տողում ավելացնում ենք
PKG_CONFIG_PATH=$PKG_CONFIG_PATH:/usr/local/lib/pkgconfig export PKG_CONFIG_PATH
Վերջ գրադարանը տեղակայված է։
Այժմ խնդիր է դրված առանձնացնել ֆիքսված դիրքով տեղակայված պետավտոհամարանիշի առանձին թվանշանները․
Բերենք կոդը՝ գրված C++ լեզվով․
DetectNumbers.h
#ifndef DETECTNUMBERS_H #define DETECTNUMBERS_H #include <baseapi.h> #include "opencv/cv.h" #include "opencv2/core/core.hpp" #include "opencv2/highgui/highgui.hpp" #include "opencv2/imgproc/imgproc.hpp" #include <opencv2/opencv.hpp> #include <string> namespace cvTech { class cvDetection; } class cvTech::cvDetection { private: std::string mPath; int mThreshold; int mMaxValue; cv::Mat mImage; public: virtual void cvShowImage(const IplImage& im); virtual void cvArrToMatrix(const IplImage& src, cv::Mat& m); virtual cv::Mat cvConverteToSmooth(cv::Mat s, size_t w, size_t h); virtual IplImage* cvCreateNewImage(const IplImage* src, int depth, int a); virtual IplImage* cvCopySourceImage(IplImage* src); virtual IplImage* cvTransformImageEx(IplImage* gray, IplImage* binary, size_t radius); virtual IplImage* cvCvtColors(); virtual IplImage* cvBinarizeImage(const IplImage* src, IplImage* gray); virtual IplImage* cvTrnasformToCanny(IplImage* morf, IplImage* gray, int a, int b, int c); virtual CvSeq* cvFindContoursInToImage(IplImage* binary); virtual void show(); public: cvDetection(const std::string& str, int threshold, int maxvalue); cvDetection(const cvDetection& d); cvDetection& operator=(const cvDetection& d); std::string cvGetImagePath() const; cv::Mat cvGetImage() const; void cvSetImagePath(const std::string& str); int cvGetThreshold() const; int cvGetMaxValue() const; }; #endif // DETECTNUMBERS_H
DetectNumbers.cpp
#include "DetectNumbers.h" #include <cassert> const char* wndname = "Detect Car Numbers"; cvTech::cvDetection::cvDetection(const std::string& str, int threshold, int maxvalue) : mPath(str) , mThreshold(threshold) , mMaxValue(maxvalue) { mImage = cv::imread(mPath, 1); } void cvTech::cvDetection::cvSetImagePath(const std::string& str) { assert(!str.empty()); mPath = str; } std::string cvTech::cvDetection::cvGetImagePath() const { return mPath; } cv::Mat cvTech::cvDetection::cvGetImage() const { return mImage; } int cvTech::cvDetection::cvGetThreshold() const { return mThreshold; } int cvTech::cvDetection::cvGetMaxValue() const { return mMaxValue; } cvTech::cvDetection::cvDetection(const cvDetection& d) { this->mPath = d.cvGetImagePath(); this->mImage = d.cvGetImage(); this->mThreshold = d.cvGetThreshold(); this->mMaxValue = d.cvGetMaxValue(); } cvTech::cvDetection& cvTech::cvDetection::operator=(const cvDetection& d) { if(&d == this) { return (*this); } this->mPath = d.cvGetImagePath(); this->mImage = d.cvGetImage(); this->mThreshold = d.cvGetThreshold(); this->mMaxValue = d.cvGetMaxValue(); return (*this); } void cvTech::cvDetection::cvShowImage(const IplImage& im) { cv::Mat temp; cvArrToMatrix(im, temp); imshow(wndname, temp); int c = cv::waitKey(); } void cvTech::cvDetection::cvArrToMatrix(const IplImage& src, cv::Mat& m) { m = cv::cvarrToMat(&src); } cv::Mat cvTech::cvDetection::cvConverteToSmooth(cv::Mat src, size_t w, size_t h) { IplImage i = mImage; IplImage* img = cvCloneImage(&i); IplImage s = src; cvSmooth(&s, img, CV_GAUSSIAN, w, h); cv::Mat m(img); return m; } IplImage* cvTech::cvDetection::cvCreateNewImage(const IplImage* src, int depth, int a) { IplImage* dst = cvCreateImage(cvSize(src->width, src->height), depth, 1); assert(dst != 0); return dst; } IplImage* cvTech::cvDetection::cvCopySourceImage(IplImage* src) { IplImage* dst = cvCloneImage(src); assert(dst != 0); return dst; } IplImage* cvTech::cvDetection::cvTransformImageEx(IplImage* gray, IplImage* binary, size_t radius) { assert(binary != 0); IplConvKernel* kern = cvCreateStructuringElementEx(radius*2, radius*2, radius, radius, CV_SHAPE_RECT); IplImage img = mImage; IplImage* temp = cvCreateImage(cvSize(img.width, img.height), img.depth, 1); IplImage* dst = cvCopySourceImage(gray); cvMorphologyEx(binary, dst, temp, kern, CV_MOP_TOPHAT,1); assert(dst != 0); return dst; } IplImage* cvTech::cvDetection::cvCvtColors() { IplImage img = mImage; IplImage* gray = cvCreateImage(cvSize(img.width, img.height), 8, 1); IplImage* img1 = cvCopySourceImage(&img); cvCvtColor(img1, gray, CV_RGB2GRAY); assert(gray!=0); return gray; } IplImage* cvTech::cvDetection::cvBinarizeImage(const IplImage* src, IplImage* gray) { IplImage img = mImage; IplImage* binary = cvCreateNewImage(src, img.depth, 1); cvThreshold(gray, binary, mThreshold, mMaxValue, CV_THRESH_BINARY); assert(binary != 0); return binary; } IplImage* cvTech::cvDetection::cvTrnasformToCanny(IplImage* morf, IplImage* gray, int a, int b, int c) { IplImage* canny = cvCopySourceImage(gray); assert(morf != 0); assert(canny != 0); cvCanny(morf, canny, a, b, c); assert(canny != 0); return canny; } CvSeq* cvTech::cvDetection::cvFindContoursInToImage(IplImage* binary) { CvSeq *ptr,*polygon; CvMemStorage *mem; mem = cvCreateMemStorage(0); CvSeq *contours = 0; IplImage img = mImage; cvFindContours(binary, mem, &contours, sizeof(CvContour), CV_RETR_LIST, CV_CHAIN_APPROX_SIMPLE, cvPoint(0,0)); for (ptr = contours; ptr != NULL; ptr = ptr->h_next) { double reg = fabs(cvContourArea(ptr, CV_WHOLE_SEQ)); // if(reg >10 && reg <600) { cvApproxPoly(ptr, sizeof(CvContour), mem, CV_POLY_APPROX_DP, 3, 1); CvScalar ext_color = CV_RGB( 255, 255, 255 ); CvRect rectEst = cvBoundingRect( ptr, 0 ); CvPoint pt1,pt2; pt1.x = rectEst.x; pt1.y = rectEst.y; pt2.x = rectEst.x+ rectEst.width; pt2.y = rectEst.y+ rectEst.height; int thickness =1 ; cvRectangle(&img, pt1, pt2, CV_RGB(80, 255, 0 ), thickness ); cvResetImageROI(&img); } } assert(contours != 0); return contours; } void cvTech::cvDetection::show() { imshow(wndname, mImage); int c = cv::waitKey(); }
main.cpp
#include "DetectNumbers.h" #include <string> int main() { namespace T = cvTech; std::string path("/home/vardan/detect/index.png"); T::cvDetection* d = new T::cvDetection(path, 100, 200 ); assert(d != 0); cv::Mat dst; cv::Mat img = d->cvGetImage(); IplImage cp = img; IplImage* sm = d->cvCopySourceImage(&cp); assert(sm != 0); cv::Mat m(sm); d->cvConverteToSmooth(m, 3, 3); IplImage* gray = d->cvCvtColors(); IplImage* binary = d->cvBinarizeImage(&cp, gray); // IplImage* tr = d->cvTransformImageEx(gray, binary, 10); // assert(tr != 0); // IplImage* canny = d->cvTrnasformToCanny(tr, gray, 100, 500, 3); // assert(canny != 0); d->cvFindContoursInToImage(binary); d->show(); if(d != 0) { delete d; } return 0; }
Makefile
EXE=DetectNumbers $(EXE) : $(EXE).cpp main.cpp $(EXE).h g++ -o $@ $^ `pkg-config opencv --cflags --libs tesseract` -ggdb .PHONY : clean clean: rm -rf $(EXE) $(EXE).o *.swf
Վերջապես ամեն ինչ արդեն պատրաստ է կարող ենք կոմպիլացնել կոդը և աշխատացնել (պետք է փոխեք պատկերի ճանապարհը ՝ /home/vardan/detect/index.png փոխարեն տալով ձեր պատկերի ճանապարհը): ՈՒնենք հետևյալ ֆայլերը DetectNumbers.h, DetectNumbers.cpp, main.cpp, makefile և դրանք գտնվում են օրինակ /home/ubuntu/opencv/my_cods/detect_car_numbers պանակում։ Կատարում ենք հետևյալ քայլերը․
1.
make
2.
./DetectNumbers
Արդյունքում կբացվի հետևյալ պատուհանը․
Տեսնում ենք, որ մեր ծրագիրը հաջող կարողացել է սեգմենտացնել պետհամարանիշի առանձին թվանշանները, բայց արդյունքը իդեալականին մոտ չէ, քանի որ առկա են բազմաթիվ մակաբուծային՝ ավելորդ կոնտուրներ։
Այդ արդյունքի համար մեղավոր է DetectNumbers.cpp ֆայլի 151 -րդ տողի փակված if(…) պայմանական անցման օպերատորը։ if(…) -ի ներսում էլ հենց ստուգվում է կոնտուրի չափերը և էկրանին պատկերվում են միայն անհրաժեշտ պայմաններին բավարարող կոնտուրները, տվյալ դեպքում if(reg >10 && reg <600) – ում ստուգվում է, եթե կոնտուրի մակերեսը մեծ է 10 -ից և փոքր է 600 -ից ապա դա համավում է թույլատրելի կոնտուր և պատկերվում է էկրանին։ Հիմա բացում ենք 151-րդ տողի այդ if(…) -ը և տեսնում․
Այս անգամ մեզ հաջողվեց բավական լավ արդյունք ստանալ։
Ինչպես համոզվեցիք ինքներդ՝ տարբեր համարանիշների դեպքում սեգմենտացման կայուն արդյունքներ ստանալու համար պետք է սստուգաճշտել կոնտուրների մակերեսը, չափսերը և այլ պարամետրեր։ Բացի այդ արդյունքների ճշտության աստիճանը կախված է նաև մուտքային պատկերի հստակության աստիճանից, մակաբուծային ստվերերի առկայությունից, համարանիշի դիրքից, անկյունից և այլն։ Ծրագրային կոդի բերված տարբերակը նախնական, սաղմնային տարբերակն է և չի կարող տալ արտադրական պահանջներին բավարարող կայուն արդյունքներ, բայց շատ և շատ դեպքերում այն թույլ է տալիս ստանալ բավականին լավ արդյունքներ։ Այս կոդը կարելի է կատարելագործել և ստանալ ավելի ստաբիլ արդյունքներ տվող ծրագիր։ Երկրորդ մասում կխոսենք OpenCV գրադարանի՝ բերված կոդում օգտագործված ֆունկցիաներից, սեգմենտացման ընդհանուր խնդիրներից և մեր ծրագրի կառուցվածքից։ Պրոյեկտի բոլոր ֆայլերը կարող էք բեռնել github.com -ի այս ռեպոզիտորիայից։
Comments: no replies