Smart Sight կամ խելացի նշանոց

| Հունիս 15, 2013 | Մեկնաբանված չէ |

             

Խելացի նշանոցի հիմնական գործառույթը կայանում է հետաքրքրող օբյեկտի ընդգծման, նրա տեղաշարժի և ուղղության հետևման, ինչպես նաև օբյեկտի ճանաչման մեջ։
Շատ կուզենայի նման բան ստանալ

Բայց նման բան ստանալու համար շատ թանկ սարքավորումներ են պետք, օրինակ thermographic camera և այլն, այնպես որ դեռ կբավարարվենք ցերեկվա լույսով 🙂 :
OpenCv պատկերների ճանաչման գրադարանը ունի բազմաթիվ ֆունկցիաներ, որոնք թույլ են բազմապիսի գործողություններ կատարել պատկերների հետ և օգտվելով գրադարանի ընձեռած հնարավորություններից, այս հոդվածում ներկայացրել ենք մարդու մարմնի ընդգծման, նրա տեղաշարժի հետևման և դեմքի ճանաչման source-երը կամ սարքածրագրային լուծումները։ Բայց  միանգամից անենք մի քանի ճշգրտումներ․

  1. ծրագրի կողմից ընդգծվում է ոչ միայն մարդը, այլ նաև ցանկացած վերջավոր չափեր ունեցող և տեսախցիկի առջև երևացող օբյեկտ, ինչպես նաև հսկվում է ցանկացած նույն պայմաններին բավարարող օբյեկտ, սակայն ի տարբերութուն այլ օբյեկտների, մարդու դեմքը ճանաչվում և լրացուցիչ ընդգծվում է ծրագրի կողմից։ Իհարկե կարելի է նաև հսկել մեկ առանձնացված օբյեկտ։ Դրա համար բավական է հետևել միայն այդ օբյեկտի որոշ կետերի օպտիկական հոսքին։
  2. Սարքային պլատֆորմները, որոնց վրա պետք է աշխատի OpenCv գրադարանը օգտագործող ծրագրերը, կարող են շատ տարբեր լինել, սկսած իմ հեռախոսից՝  600 mghz անոց ARM ճարտարապետությամբ սմարթֆոնից, վերջացրած շատ ավելի հզոր անձնական կամ լաբորատոր համակարգիչներով կամ կլաստերներով, այստեղ պայմանն է այն է, որ ինչքան հզոր եղավ պլատֆորմը, այնքան արագ կաշխատի ծրագիրը։ Չնայած OpenCv գրադարանում անհամեմատ ավելի շատ են ծանր ալգորիթմները, որոնց համար 600 mghz անոց պլատֆորմը չի կարող լուրջ և պահանջներին բավարարող պլատֆորմ համարվել։ Օրինակ մարդու դեմքի ճանաչման Վիոլա Ջոնսի ալգորիթմը շատ դանդաղ է աշխատում անգամ core to quad q9550, 4ggb ram ունեցող իմ համակարգչում, դե էլ չասեմ թե ինչպես այն կաշխատի 600 mghz անոց կամ այլ համեմատական հնարավորություններ ունեցող սմարթֆոններում։
Վերը բերված վիդեոյում, ձախից ներքևի կողմում, անգույն նկարում բերված է ընդգծված մարմինների շարժման հետևման պատկերը․ այստեղ սև գծերը ցույց են տալիս օբյեկտին պատկանող կետերի տեղաշարժը, ասենք օրինակ, եթե օբյեկտին պատկանող կետը տեղաշարժվելով A կետից տեղափոխվել է B կետ, ապա սև գծերը ցույց են տալիս հենց այդ  A և B կետերը միացնող ուղիղը։ Այսպիսով մենք կարողնում են որոշել օբյեկտի շարժման ուղությունը։ Վերը բերված վիդեոյում վերևի շարքի նկարները ցույց են տալիս մարդու դեմքի ճանաչումն ու ընդգծումը։
Բերենք source -երը։

SmartSight.h

#ifndef SMARTSIGHT_H
#define SMARTSIGHT_H

#include <baseapi.h>
#include <opencv2/opencv.hpp>
#include <string>
#include <vector>

#include "opencv/cv.h"
#include "opencv2/core/core.hpp"
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include <opencv2/opencv.hpp>
#include <opencv2/opencv.hpp>

namespace cvTech
{
	class cvSmartSight;
}

class cvTech::cvSmartSight
{
	// typedef types
	private:
		typedef std::vector<cv::Point2f> Corner;
		Corner m_corners;
		Corner m_second_corners;

	// static member variables
	private:
		static const double m_qualityLevel;
		static const double m_min_distance;
		static const int m_block_size;
		static const bool m_Harris_detector;
		static const double m_k;
		static const int m_max_corners;
		static const int m_max_trackbar;
		static const std::string m_cascadeName;
		static const std::string m_nestedCascadeName;

	// virtual methods
	public:
 		virtual IplImage* cvCreateNewImage(const IplImage* src, int depth, int a);

		virtual IplImage* cvCopySourceImage(IplImage* src);

		virtual IplImage* cvCvtColors(cv::Mat& image);

		virtual cv::Mat cvBinarizeImage(cv::Mat src, cv::Mat gray);

		virtual CvSeq* cvFindContoursInToImage(cv::Mat image, cv::Mat o);

 		virtual void cvShowImage(const IplImage& im);

		virtual void cvArrToMatrix(const IplImage& src, cv::Mat& m);

		virtual void cvAdaptiveConversion(cv::Mat& img, cv::Mat& org, cv::Mat& adpt);

		virtual void cvGoodFeaturesToTrack(cv::Mat frame, Corner& m_corners);

		virtual void cvCornerSubPix(cv::Mat frame, Corner& corner);

		virtual void cvOpticalFlow(cv::Mat prev, cv::Mat next, 
				std::vector<uchar>& features_found, 
				std::vector<float>& feature_errors, Corner& c1, Corner& c2);

		virtual void cvLineDraw(IplImage img, Corner corners,
				Corner second_corners,
				std::vector<uchar>& features_found,
				std::vector<float>& feature_errors); 

		virtual void cvMotionDetection(cv::Mat prev_frame, cv::Mat next_frame);

		virtual void cvSightingAtTheObject(cv::Mat& org);

		virtual void FaceDetect(cv::Mat& img, cv::CascadeClassifier& cascade, 
				cv::CascadeClassifier& nestedCascade, double scale);

		virtual bool CheckLines(CvPoint p0, CvPoint p1);

		virtual void show();

	// non static methods
	public:

	// Default constructor	
		cvSmartSight();
};

#endif // SMARTSIGHT_H

SmartSight.cpp

#include "SmartSight.h"

#include <cassert>

const double cvTech::cvSmartSight::m_qualityLevel = 0.01;
const double cvTech::cvSmartSight::m_min_distance = 10;
const int cvTech::cvSmartSight::m_block_size = 3;
const bool cvTech::cvSmartSight::m_Harris_detector = false;
const double cvTech::cvSmartSight::m_k = 0.04;
const int cvTech::cvSmartSight::m_max_corners = 300;
const int cvTech::cvSmartSight::m_max_trackbar = 100;
const std::string cvTech::cvSmartSight::m_cascadeName = "./data/haarcascades/\
haarcascade_frontalface_alt.xml";
const std::string cvTech::cvSmartSight::m_nestedCascadeName = "./data/haarcascades/\
haarcascade_eye_tree_eyeglasses.xml";

cvTech::cvSmartSight::cvSmartSight()
{
}

void cvTech::cvSmartSight::cvShowImage(const IplImage& im)
{
	cv::Mat temp;
    cvArrToMatrix(im, temp);
	imshow("wndname", temp);
	int c = cv::waitKey();
}

void cvTech::cvSmartSight::cvArrToMatrix(const IplImage& src, cv::Mat& m)
{
	m = cv::cvarrToMat(&src);
}

IplImage* cvTech::cvSmartSight::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::cvSmartSight::cvCopySourceImage(IplImage* src)
{
	IplImage* dst = cvCloneImage(src);
	assert(dst != 0);
	return dst;
}

IplImage* cvTech::cvSmartSight::cvCvtColors(cv::Mat& image)
{
	IplImage* gray = cvCreateImage(cvSize(image.size().width, image.size().height), 8, 1);
	IplImage img = image;
	cvCvtColor(&img, gray, CV_RGB2GRAY);
	assert(gray!=0);
	return gray;
}

cv::Mat cvTech::cvSmartSight::cvBinarizeImage(cv::Mat src, cv::Mat gray)
{
	cv::Mat binary = gray.clone();
	threshold(gray, binary, 150, 255, CV_THRESH_BINARY);
	return binary;
}

void cvTech::cvSmartSight::cvGoodFeaturesToTrack(cv::Mat frame, Corner& corners)
{
	goodFeaturesToTrack(frame, 
			corners,
			m_max_corners,
			m_qualityLevel,
			m_min_distance,
			cv::Mat(),
			m_block_size,
			m_Harris_detector,
			m_k);
}

void cvTech::cvSmartSight::cvCornerSubPix(cv::Mat frame, Corner& corners)
{
	cornerSubPix(frame, 
			corners,
			cvSize( 10, 10 ) ,
			cvSize( -1, -1 ), 
			cvTermCriteria( CV_TERMCRIT_ITER | CV_TERMCRIT_EPS, 20, 0.03 ) );
}

void cvTech::cvSmartSight::cvOpticalFlow(cv::Mat prev, cv::Mat next, 
		std::vector<uchar>& features_found, 
		std::vector<float>& feature_errors, 
		Corner& c1, 
		Corner& c2)
{
	features_found.reserve(m_max_corners);
	feature_errors.reserve(m_max_corners);
	calcOpticalFlowPyrLK(prev, 
						 next, 
						 c1, 
						 c2, 
						 features_found, 
						 feature_errors, 
						 cvSize( 10, 10 ), 
						 5,
						 cvTermCriteria( CV_TERMCRIT_ITER | 
						 CV_TERMCRIT_EPS, 20, 0.3 ), 0);
}

void cvTech::cvSmartSight::cvLineDraw(IplImage img,	Corner corners, 
		Corner second_corners, std::vector<uchar>& features_found, 
		std::vector<float>& feature_errors)
{
	for( int i = 0; i < m_max_corners; ++i )
	{
		if( features_found[i] == 0 || feature_errors[i] > m_max_corners ) 
		{
			continue;
		}

		CvPoint p0 = cvPoint( cvRound( corners[i].x ), cvRound( corners[i].y ) );
		CvPoint p1 = cvPoint( cvRound( second_corners[i].x ), cvRound( second_corners[i].y ) );
		if (sqrt(pow(p0.x - p1.x, 2) + pow(p0.y - p1.y, 2)) < 10)
		{ 
			continue;
		}
		if(!CheckLines(p0, p1))
		{
			continue;
		}
		cvLine(&img, p0, p1, CV_RGB(255,0,0), 3, CV_AA);
	}
	cv::Mat o(&img);
	cv::imshow("Motion Direction", o);  
	int key = cv::waitKey(5);
}

void cvTech::cvSmartSight::cvMotionDetection(cv::Mat prev_frame, cv::Mat next_frame)
{
	cv::Mat prev, next;
	std::vector<uchar> features_found;
	std::vector<float> feature_errors;
	typedef cvTech::cvSmartSight T;
	T::Corner corners;
	T::Corner second_corners;
	cvtColor(prev_frame, prev, CV_BGR2GRAY); 
	cvtColor(next_frame, next, CV_BGR2GRAY); 
	cvGoodFeaturesToTrack(prev, corners);
	cvCornerSubPix(prev, corners);
	cvOpticalFlow(prev, next, features_found, feature_errors, 
			corners, second_corners);
	cvLineDraw(next, corners, second_corners, features_found, feature_errors);
}

void cvTech::cvSmartSight::cvAdaptiveConversion(cv::Mat& img, cv::Mat& org, cv::Mat& adpt)
{
	IplImage tmp = org;
	IplImage* adaptiv = cvCreateImage( cvSize(tmp.width, tmp.height), tmp.depth, 1);
	IplImage b = img;
	cvAdaptiveThreshold(&b, adaptiv, 250, CV_ADAPTIVE_THRESH_GAUSSIAN_C, CV_THRESH_BINARY, 7, 1);
	cvArrToMatrix(*adaptiv, adpt);
}

bool cvTech::cvSmartSight::CheckLines(CvPoint p0, CvPoint p1)
{
	if(fabs(p0.x - p1.x) <= 100 && fabs(p0.y - p1.y) <= 100)
	{
		return true;
	}
	return false;
}

void cvTech::cvSmartSight::cvSightingAtTheObject(cv::Mat& org)
{
	cv::CascadeClassifier cascade, nestedCascade;
    double scale = 1;
	IplImage* gray = 0;
	cv::Mat adpt;
	gray = cvCvtColors(org);
	cv::Mat g(gray);
	cv::Mat binary = cvBinarizeImage(org, g);
	cv::Mat tmp(binary);
	cvAdaptiveConversion(tmp, org, adpt);
	IplImage o = org;
	cvFindContoursInToImage(adpt, &o);
    if( !cascade.load(m_cascadeName ) )
    {
	std::cerr << "ERROR: Could not load classifier cascade" << std::endl;
        return;
    }
	FaceDetect(org, cascade, nestedCascade, scale );
	cv::waitKey(5);
}

CvSeq* cvTech::cvSmartSight::cvFindContoursInToImage(cv::Mat image, cv::Mat org)
{
	std::vector<cv::Vec4i> hierarchy;
	std::vector<std::vector<cv::Point> > contours;
	cv::Mat temp = image.clone();
	std::vector<cv::Point> approx;
	IplImage o = org;

	findContours(temp, contours, hierarchy, CV_RETR_EXTERNAL, /*CV_CHAIN_APPROX_NONE*/CV_LINK_RUNS, cv::Point(0, 0) );
	if(!contours.empty())
	{
		for(int i = 0; i < contours.size(); i++)
		{
			cv::Mat m(contours[i]);
			IplImage t = m;

			t.imageData = (char *) m.data;
			double reg = fabs(contourArea(contours[i]));
			if(reg > 1000 /*  && reg <22000*/)
			{
				approxPolyDP(contours[i], approx, 3, 1);
				cv::Scalar color( 50, 0, 255 );
				drawContours(org, contours, i, color, 3, 8, hierarchy, 1);
				CvRect rectEst = boundingRect(contours[i]);
				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 ;
				IplImage tmp = o;
				cvRectangle(&tmp, pt1, pt2, CV_RGB(80, 255, 0 ), thickness );
				cvResetImageROI(&tmp);
				cv::Mat f(&tmp);
				cv::Mat img_mat = cv::cvarrToMat(&tmp);
				cv::imshow("dst", img_mat);
			}
		}
	}
}

void cvTech::cvSmartSight::FaceDetect(cv::Mat& img, cv::CascadeClassifier& cascade, 
				cv::CascadeClassifier& nestedCascade, double scale)
{
    int i = 0;
	std::vector<cv::Rect> faces;
    const static cv::Scalar colors[] =  { CV_RGB(0,0,255),
        CV_RGB(0,128,255),
        CV_RGB(0,255,255),
        CV_RGB(0,255,0),
        CV_RGB(255,128,0),
        CV_RGB(255,255,0),
        CV_RGB(255,0,0),
        CV_RGB(255,0,255)} ;
	cv::Mat gray, smallImg( cvRound (img.rows/scale), cvRound(img.cols/scale), CV_8UC1 );

    cvtColor( img, gray, CV_BGR2GRAY );
	cv::resize( gray, smallImg, smallImg.size(), 0, 0, cv::INTER_LINEAR );
    equalizeHist( smallImg, smallImg );
    //equalizeHist( smallImg, smallImg );

    cascade.detectMultiScale( smallImg, faces,
        1.1, 2, 0
        |CV_HAAR_SCALE_IMAGE
        ,
        cv::Size(30, 30) );
    for( std::vector<cv::Rect>::const_iterator r = faces.begin(); r != faces.end(); r++, i++ )
    {
		cv::Mat smallImgROI;
		std::vector<cv::Rect> nestedObjects;
		cv::Point center;
		cv::Scalar color = colors[i%8];
        int radius;
        center.x = cvRound((r->x + r->width*0.5)*scale);
        center.y = cvRound((r->y + r->height*0.5)*scale);
        radius = cvRound((r->width + r->height)*0.25*scale);
        circle( img, center, radius, color, 3, 8, 0 );
        circle( img, center, radius/3, color, 3, 8, 0 );
		cv::Point p0(center.x, center.y + radius/3);
		cv::Point p1(center.x, center.y - radius/3);
		cv::Point p2(center.x + radius/3, center.y);
		cv::Point p3(center.x - radius/3, center.y);
		line(img, p0, p1, CV_RGB(255,0,0), 3, CV_AA );
		line(img, p2, p3, CV_RGB(255,0,0), 3, CV_AA );
        if( nestedCascade.empty() )
            continue;
        smallImgROI = smallImg(*r);
        nestedCascade.detectMultiScale( smallImgROI, nestedObjects,
            1.1, 2, 0
            |CV_HAAR_SCALE_IMAGE
            ,
            cv::Size(30, 30) );
    }
    cv::imshow( "result", img );
}

void cvTech::cvSmartSight::show()
{
//	cv::Mat temp;
  //  cvArrToMatrix(*mImage, temp);
//	imshow(wndname, mImage);
//	int c = cv::waitKey();
}

main.cpp

#include "SmartSight.h"

#include <string>

const std::string cascadeName = "./data/haarcascades/\
haarcascade_frontalface_alt.xml";
const  std::string nestedCascadeName = "./data/haarcascades/\
haarcascade_eye_tree_eyeglasses.xml";
int main()
{
	typedef cvTech::cvSmartSight T;
	T o;
	cv::VideoCapture cap(0); 
	if(!cap.isOpened())              
	{
		std::cout<<"[!] Error: cant open camera!"<<std::endl;
		return -1;
	}
	cv::Mat edges;
	cv::CascadeClassifier cascade, nestedCascade;
    double scale = 1;
	cv::namedWindow("result window", 1);
	cv::Mat currFrame, frame, frame2, tmp;
	cap >> frame;
	currFrame = frame.clone();
	while(1)
	{
		cap >> frame2;
		cv::imshow("Original Frame", frame);
		o.cvSightingAtTheObject(currFrame);
		o.cvMotionDetection(currFrame, frame2);
		cv::imshow("face", currFrame);
		currFrame = frame2.clone();
	}
	return 0;
}

makefile

EXE=SmartSight
$(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

Կոդը բավականին երկար է և ամբողջ կոդի բացատրությունը չենք բերի, փոխարենը կբերենք միայն կարևորագույն ֆունկցիաների բացատրությունը։
main.cpp -ի մեջ կանչվում են մեր գրած հետևյալ կարևորագույն ֆունկցիաները․

cvSightingAtTheObject(currFrame);
cvMotionDetection(currFrame, frame2);

cvSightingAtTheObject ֆունկցիան որպես պարամետր ստանում է ընթացիկ կադրը web camera -ից։

void cvTech::cvSmartSight::cvSightingAtTheObject(cv::Mat& org)
{
	cv::CascadeClassifier cascade, nestedCascade;
    double scale = 1;
	IplImage* gray = 0;
	cv::Mat adpt;
	gray = cvCvtColors(org);
	cv::Mat g(gray);
	cv::Mat binary = cvBinarizeImage(org, g);
	cv::Mat tmp(binary);
	cvAdaptiveConversion(tmp, org, adpt);
	IplImage o = org;
	cvFindContoursInToImage(adpt, &o);
    if( !cascade.load(m_cascadeName ) )
    {
		std::cerr << "ERROR: Could not load classifier cascade" << std::endl;
		std::cerr << "Usage: facedetect [--cascade=<cascade_path>]\n"
            "   [--nested-cascade[=nested_cascade_path]]\n"
            "   [--scale[=<image scale>\n"
            "   [filename|camera_index]\n" << std::endl ;
        return;
    }
	FaceDetect(org, cascade, nestedCascade, scale );
	cv::waitKey(5);
}

Ընդհանրապես պատկերների ճանաչման և կոնտուրային վերլուծության գործընթացը բաղկացած է հետևյալ փուլերից․

  1. պատկերի նախնական մշակում․ նախնական զտում, կոնտրաստի մեծացում,
  2. մուտքային պատկերի բինարիզացիա կամ երկուականացում, այսինքն պատկերի նեկայացում միայն սև և սպիտակ գույներով և հենց աստեղ է, որ կարող ենք ընդհանուր ֆոնից օբյեկտի նախնական զտում իրականացնել՝ ֆոնը պատկերելով սև գույնով, իսկ հետաքրքրող օբյեկտը սպիտակ։
  3. կոնտուրների առանձնացում,
  4. կոնտուրների զտում, ըստ մակերեսի պարագծի և այլ երկրաչափական պարամետրերի,
  5. գտնված կոնտուրների վերլուծություն։

Հենց այս սխեմայով էլ վարվել ենք մենք։
7-րդ տողում պարամետրով ստացված օրիգինալ պատկերից ստանում ենք նույն չափի մոխրագույն պատկեր և պահում ենք gray փոփոխականի մեջ։
9-րդ տողում binary փոփոխականում ստանում ենք նույն չափի երկուական պատկեր։ Երկուական պատկերը իրենից ներկայացնում է պատկեր, որը ունի երկու գույն սև և սպիտակ։ cvAdaptiveConversion ֆունկցիայի միջոցով կատարվում է շեմային ձևափոխություն։ Ընդանհրապես պատկերը իրենից ներկայացնում է պիքսելների զանգված, իսկ շեմային ձևափոխություններն օգատգործվում են մուտքային նկարից այն պիքսելների առանձնացման համար, որոնց արժեքը համեմատական է cvAdaptiveThreshold ֆունկցիայում տրված շեմային արժեքի հետ։ Ադապտիվ ձևափոխությունը անհրաժեշտ է այն դեպքերւմ, երբ մուտքային պատկերի վրա առկա են շատ լուսավոր, փայլող կամ ընդհակառակը մութ կամ ստվերոտ տեղեր։ Այդ դեպքում findContours ֆունկցիան չի կարող գտնել իրական օբյեկտին համապատասխան կոնտուրները ևդրա համար այդ դեպքերում այս ֆունկցիայի օգտագործումը անհրաժեշտություն է։

 

Binary_and_adaptive_threshold

 

 

 

Այժմ արդեն զտված մուտքային ապտկերը տալիս ենք cvFindContoursInToImage ֆունկցիային, գտնում ենք օբյեկտներին պատկանող կոնտուրնեը և ընդգծում ենք դրանք կարմիր գույնով։ Այնուհետև նույն cvSightingAtTheObject ֆունկցիայում կանչում ենք FaceDetect ֆունկցիան և որպես պարամետր տալիս ենք մուտքային չզտված պատկերը և կատարում ենք մարդկանց դեմքերի որոնում՝ օգտագործելով Հաարի դասակարգիչը։ Հաարի դասակարգիչը ստանալով մուտքային պատկերը կատարում է դեմքի փնտրում՝ օգտագործելով Վիոլա Ջոնսի ալգորիթմը և OpenCv-ի ռեպոզիտորիայի հետ եկող ../opencv/data/ պանակում եղած Հաարի ուսուցման կասկադները։ Դեմքի դիմային հատվածի ճանաչման կասկադները գտնվում են haarcascade_frontalface_alt2.xml ֆայլում։
cvMotionDetection ֆունկցիայում կատարվում է օբյեկտին պատկանող կետերի տեղաշարժի հետևում։ Բերենք այստեղ օգտագործված ֆունկցիաների բացատրությունը․
)

void cvGoodFeaturesToTrack(InputArray image, OutputArray corners, int maxCorners, double qualityLevel, double minDistance, InputArray mask=noArray(), int blockSize=3, bool useHarrisDetector=false, double k=0.04 )

Ֆունկցիայի միջոցով կատարվում է օբյեկտին պատկանող եզրերի որոնում։

Parameters:
image – մուտքային 8-բիթ կամ floating-point 32-բիթ, միականալային պատկեր.
eig_image –պարամետրը հաշվի չի առնվում
temp_image – պարամետրը հաշվի չի առնվում
corners – օբյեկտի գտնված եզրերը պարունակող վեկտոր
maxCorners – Վերադարձվող եզրերի առավելագույն քանակը։
qualityLevel – Parameter characterizing the minimal accepted quality of image corners. Պարամետրը բնորոշում է եզրերը պարունակող պատկերի նվազագույն թույլատրելի որակը,
minDistance – վերադարձվող եզրերի միջև նվազագույն հեռավորությունը
mask – հավելյալ հետաքրքրող ռեգիոն
blockSize – յուրաքանչյուր պիքսելին շրջապատող տարածքի հատվածի միջին չափը
useHarrisDetector – պարամետրով տրվում է օգտագործել Հարիսի դետեկտորը, թե ոչ,
k – Հարիսի դետեկտորին վերաբերվող ազատ պարամետր։

void cornerSubPix(InputArray image, InputOutputArray corners, Size winSize, Size zeroZone, TermCriteria criteria)

Ճշտում է օբյեկտի եզրերի անկյունների գտնվելու տեղերը
Parameters:
image – մուտքային պատկեր.
corners – Մուտքային եզրերի սկզբնական կոորդինատները,
winSize – փնտրման պատուհանի կողային մասեր կեսը,
zeroZone – այս պարամետրի արժեքը սովորաբար դրվում է cvSize(-1,-1),
criteria – անկյան ճշգրտումների իտերացիոն պրոցեսսի դադարաման չափանիշ

calcOpticalFlowPyrLK() ֆունկցիան հաշվարկում է օպտիկական հոսքը Լուկաս-Կանդայի բրգաձև մեթոդով, պարզ ասած հետևում է կետերի տեղաշարժին։

void calcOpticalFlowPyrLK(InputArray prevImg, InputArray nextImg, InputArray prevPts, InputOutputArray nextPts, OutputArray status, OutputArray err, Size winSize=Size(21,21), int maxLevel=3, TermCriteria criteria=TermCriteria(TermCriteria::COUNT+TermCriteria::EPS, 30, 0.01), int flags=0, double minEigThreshold=1e-4 )

Parameters:
prevImg – 8 բիթանի մուտքային պատկեր,
nextImg – հաջորդ մուտքային պատկերը,
prevPts – այն 2D կետերի վեկտորը, որոնց օպտիկական հոսքը պետք է գտնել,
nextPts – ելքային 2D վեկտոր, որը պարունակում է մուտքային կետերի հաշվարկված նոր դիրքերը երկրորդ պատկերի վրա,
status – output status vector (of unsigned chars); each element of the vector is set to 1 if the flow for the corresponding features has been found, otherwise, it is set to 0.
err – սխալների ելքային վեկտոր,
winSize – փնտրման պատուհանի չափ,
maxLevel – օգտագործվող բուրգերի կամ մակարդակների մաքսիմալ քանակը,
criteria – պարամետր է, որը ցույց է տալիս, փնտրման իտերատիվ ալգորիթմի ավարտը (տրված maxCount առավելագույն քանակով իտերացիաներից հետո կամ երբ փնտրման պատուհանում քայլը փոքր է քան epsilon -ը)
flags –գործողության ֆլագեր
OPTFLOW_USE_INITIAL_FLOW
OPTFLOW_LK_GET_MIN_EIGENVALS սրանցից ես էլ գլուխ չհանեցի դրեցի նենց, ոնց տրված էր OpenCV documentation -ի կայքում։
minEigThreshold –այս պարամետրով հաշվարկվում է օպտիակական հոսքի երկչափանի 2×2 մատրիցի սեփական նվազագույն արժեքները՝ բաժանած պատուհանում պիքսելների քանակի վրա։
Մի խոսքով այս երեք ֆունկցիաների միջոցով նախ կատարվում է հետաքրքրող օբյեկտի եզրերի որոնում, այնուհետև ճշգրտվում է եզրերի անկյունները, հետո էլ camera -ից ստացված օբյեկտի երկու հաջորդական պատկերների (frame)-ի հիման վրա կատարվում է օբյեկտի կետերի տեղաշարժի հետևում։

Smart Sight կամ խելացի նշանոց, 10.0 out of 10 based on 17 ratings

Նշագրեր: , , ,

Բաժին: *Nix-եր, C և C++, WIndows, Ծրագրավորման լեզուներ, Ծրագրավորում

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

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

Մեկնաբանեք

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

259