Սկիզբ » Ուսումնական նյութեր » Օպերացիոն համակարգեր » *Nix-եր » OpenCv մեքենայական տեսողության գրադարանի տեղակայում և ֆիքսված դիրքով պետավտոհամարանիշների սեգմենտացում՝ առանձին թվանշանների առանձնացում։ Մաս 1։

OpenCv մեքենայական տեսողության գրադարանի տեղակայում և ֆիքսված դիրքով պետավտոհամարանիշների սեգմենտացում՝ առանձին թվանշանների առանձնացում։ Մաս 1։

| Մայիս 21, 2013 | Մեկնաբանված չէ |

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

Արդյունքում կբացվի հետևյալ պատուհանը․

Screenshot from 2013-05-21 19:19:14
Տեսնում ենք, որ մեր ծրագիրը հաջող կարողացել է սեգմենտացնել պետհամարանիշի առանձին թվանշանները, բայց արդյունքը իդեալականին մոտ չէ, քանի որ առկա են բազմաթիվ մակաբուծային՝ ավելորդ կոնտուրներ։
Այդ արդյունքի համար մեղավոր է DetectNumbers.cpp ֆայլի 151 -րդ տողի փակված if(…) պայմանական անցման օպերատորը։ if(…) -ի ներսում էլ հենց ստուգվում է կոնտուրի չափերը և էկրանին պատկերվում են միայն անհրաժեշտ պայմաններին բավարարող կոնտուրները, տվյալ դեպքում if(reg >10 && reg <600) – ում ստուգվում է, եթե կոնտուրի մակերեսը մեծ է 10 -ից և փոքր է 600 -ից ապա դա համավում է թույլատրելի կոնտուր և պատկերվում է էկրանին։ Հիմա բացում ենք 151-րդ տողի այդ if(…) -ը և տեսնում․

Screenshot from 2013-05-21 19:35:52
Այս անգամ մեզ հաջողվեց բավական լավ արդյունք ստանալ։

Ինչպես համոզվեցիք ինքներդ՝ տարբեր համարանիշների դեպքում սեգմենտացման կայուն արդյունքներ ստանալու համար պետք է սստուգաճշտել կոնտուրների մակերեսը, չափսերը և այլ պարամետրեր։ Բացի այդ արդյունքների ճշտության աստիճանը կախված է նաև մուտքային պատկերի հստակության աստիճանից, մակաբուծային ստվերերի առկայությունից, համարանիշի դիրքից, անկյունից և այլն։ Ծրագրային կոդի բերված տարբերակը նախնական, սաղմնային տարբերակն է և չի կարող տալ արտադրական պահանջներին բավարարող կայուն արդյունքներ, բայց շատ և շատ դեպքերում այն թույլ է տալիս ստանալ բավականին լավ արդյունքներ։ Այս կոդը կարելի է կատարելագործել և ստանալ ավելի ստաբիլ արդյունքներ տվող ծրագիր։ Երկրորդ մասում կխոսենք OpenCV գրադարանի՝ բերված կոդում օգտագործված ֆունկցիաներից, սեգմենտացման ընդհանուր խնդիրներից և մեր ծրագրի կառուցվածքից։ Պրոյեկտի բոլոր ֆայլերը կարող էք բեռնել github.com -ի այս ռեպոզիտորիայից։

OpenCv մեքենայական տեսողության գրադարանի տեղակայում և ֆիքսված դիրքով պետավտոհամարանիշների սեգմենտացում՝ առանձին թվանշանների առանձնացում։ Մաս 1։, 10.0 out of 10 based on 17 ratings

Նշագրեր: , , ,

Բաժին: *Nix-եր, C և C++, Ալգորիթմներ, Լինուքս/Յունիքս հրամաններ, Ծրագրավորում, Կոմպիլյատորներ

Կիսվել , տարածել , պահպանել

VN:F [1.9.20_1166]
Rating: 10.0/10 (17 votes cast)

Մեկնաբանեք

Կհաստատվեն միայն մեսրոպատառ հայերենով գրած մեկնաբանությունները

274