void TrackerMedianFlowImpl::check_NCC(const Mat& oldImage,const Mat& newImage, const std::vector<Point2f>& oldPoints,const std::vector<Point2f>& newPoints,std::vector<bool>& status){ std::vector<float> NCC(oldPoints.size(),0.0); Size patch(30,30); Mat p1,p2; for (int i = 0; i < (int)oldPoints.size(); i++) { getRectSubPix( oldImage, patch, oldPoints[i],p1); getRectSubPix( newImage, patch, newPoints[i],p2); const int N=900; double s1=sum(p1)(0),s2=sum(p2)(0); double n1=norm(p1),n2=norm(p2); double prod=p1.dot(p2); double sq1=sqrt(n1*n1-s1*s1/N),sq2=sqrt(n2*n2-s2*s2/N); double ares=(sq2==0)?sq1/abs(sq1):(prod-s1*s2/N)/sq1/sq2; NCC[i] = (float)ares; } float median = getMedian(NCC); for(int i = 0; i < (int)oldPoints.size(); i++) { status[i] = status[i] && (NCC[i]>median); } }
float CustomSIFT::getSubpixBlur(const Mat& img, Point2f off,KeyPoint p, double blur, map<double,Mat> &blurred) { Mat use; if (blur < 1) { use=img; } else { if (blurred.find(blur) == blurred.end()) { Mat b; int size = (int)std::ceil(2*blur); size += size%2==0?1:0; GaussianBlur(img,b,Size(size,size),blur,blur); blurred[blur]=b; } use = blurred[blur]; } Mat patch; Point2f pt (off.x+p.pt.x, off.y+p.pt.y); getRectSubPix(use, cv::Size(1,1), pt, patch); assert(patch.type() == CV_32F); float ret = patch.at<float>(0,0); assert(ret==ret); return ret; }
//TODO this should blur the image before sampling. Maybe. Vec2f CustomSIFT::getSubpix(const Mat& img, Point2f off,KeyPoint p) { Mat patch; Point2f pt (off.x+p.pt.x, off.y+p.pt.y); getRectSubPix(img, cv::Size(1,1), pt, patch); return patch.at<Vec2f>(0,0); }
Mat deskew(Mat img, double angle) { bitwise_not(img, img); vector<Point> points; Mat_<uchar>::iterator it = img.begin<uchar>(); Mat_<uchar>::iterator end = img.end<uchar>(); for (; it != end; ++it) if (*it) points.push_back(it.pos()); RotatedRect box = minAreaRect(Mat(points)); Mat rot_mat = getRotationMatrix2D(box.center, angle, 1); Mat rotated; warpAffine(img, rotated, rot_mat, img.size(), INTER_CUBIC); Size box_size = box.size; if (box.angle < -45.) swap(box_size.width, box_size.height); Mat cropped; getRectSubPix(rotated, box_size, box.center, cropped); return cropped; }
double getSubpix(const Mat& img, float x, float y, KeyPoint p) { Mat patch; Point2f pt (x+p.pt.x,y+p.pt.y); getRectSubPix(img, cv::Size(1,1), pt, patch); return patch.at<int>(0,0); }
bool ASM_Gaze_Tracker::calculatePupilCenter(){ Mat leftEyeImg,rightEyeImg,cropped; if (isTrackingSuccess == false) { return false; } canthusPts = vector<Point2f>(tracker.points.begin(),tracker.points.begin()+4); nosePts = vector<Point2f>(tracker.points.begin()+4,tracker.points.begin()+6); if (canthusPts[2].x < canthusPts[0].x && canthusPts[0].x < canthusPts[1].x && canthusPts[1].x < canthusPts[3].x) { } else { return false; } eyePairTileAngle = calculateEyePairTileAngle(canthusPts); glabellaPoint= caculateEyePairCenter(canthusPts); rotationMatrix = getRotationMatrix2D(glabellaPoint, eyePairTileAngle, 1.0); Mat Mback = getRotationMatrix2D(glabellaPoint, -eyePairTileAngle, 1.0); vector<Point2f> rotatedCanthusPts = rotatePointsByRotationMatrix(canthusPts, rotationMatrix); vector<Point2f> rotatedNosePts = rotatePointsByRotationMatrix(nosePts, rotationMatrix); float eyePairRectWidth =abs(rotatedCanthusPts[2].x - rotatedCanthusPts[3].x)+1; Size2f eyePairRectSize(eyePairRectWidth,eyePairRectWidth/7); Rect cropRect(Point2f(glabellaPoint.x-eyePairRectWidth/2,glabellaPoint.y -eyePairRectWidth/14.0f),eyePairRectSize); warpAffine(im, rotated_img, rotationMatrix, im.size(),CV_INTER_LINEAR); getRectSubPix(rotated_img, eyePairRectSize, glabellaPoint, cropped); Rect leftEyeRect = Rect(0,0,rotatedCanthusPts[0].x-rotatedCanthusPts[2].x,eyePairRectSize.height); Rect rightEyeRect = Rect(rotatedCanthusPts[1].x-rotatedCanthusPts[2].x,0,rotatedCanthusPts[3].x-rotatedCanthusPts[1].x,eyePairRectSize.height); if (leftEyeRect.area() < 50 || rightEyeRect.area()< 50) { return false; } Point2f leftEyeCenter, rightEyeCenter; // findEyeCenterByColorSegmentation(cropped(leftEyeRect), leftEyeCenter); // findEyeCenterByColorSegmentation(cropped(rightEyeRect), rightEyeCenter); // cout<<"debug"<<endl; boost::thread leftEyeThread(findEyeCenterByColorSegmentation, cropped(leftEyeRect), boost::ref(leftEyeCenter), 0.4,3,3,5); boost::thread rightEyeThread(findEyeCenterByColorSegmentation, cropped(rightEyeRect), boost::ref(rightEyeCenter), 0.4,3,3,5); leftEyeThread.join(); rightEyeThread.join(); leftEyeCenter += Point2f(leftEyeRect.tl().x,leftEyeRect.tl().y); leftEyeCenter += Point2f(cropRect.tl().x, cropRect.tl().y); rightEyeCenter += Point2f(rightEyeRect.tl().x,rightEyeRect.tl().y); rightEyeCenter += Point2f(cropRect.tl().x,cropRect.tl().y); leftEyePoint= rotatePointByRotationMatrix(leftEyeCenter, Mback); rightEyePoint= rotatePointByRotationMatrix(rightEyeCenter, Mback); isTrackingSuccess = true; return true; }
void FaceDetector::run(){ CascadeClassifier cascade; if (!cascade.load("res/haarcascade_frontalface_alt.xml") ) { qDebug() << "Erreur lors du chargement du haar cascade frontalface..."; exit(0); } QSize processSize = keepAspectRatio(_image.cols, _image.rows, MAX_PROCESS_WIDTH, MAX_PROCESS_HEIGHT); Mat color; if ( _image.cols > processSize.width() ){ cv::resize( _image, color, cv::Size(processSize.width(), processSize.height() ) ); } else { color = _image.clone(); } QSize displaySize = keepAspectRatio(color.cols, color.rows); _ratio = (double) color.cols/displaySize.width(); Mat gray; cvtColor(color, gray, CV_BGR2GRAY); //PRETRAITEMENT equalizeHist(gray, gray); vector<Rect> facesRects; cascade.detectMultiScale(gray, facesRects, 1.1, 2, 0|CV_HAAR_SCALE_IMAGE, cvSize(16,16)); // qDebug() << "detected faces size: " << facesRects.size(); for (unsigned int i = 0; i < facesRects.size(); ++i){ Rect r = facesRects[i]; Mat croppedFace; getRectSubPix(color, Size(r.width, r.height), Point2f(r.x + r.width/2, r.y + r.height / 2), croppedFace); // qImageFaces << Mat2QImage(croppedFace); struct DetectorData tmpData; tmpData.id = i; cv::resize( croppedFace, croppedFace, Size(WORK_SIZE,WORK_SIZE) ); tmpData.image = Mat2QImage(croppedFace); emit sendFace( tmpData.image ); tmpData.rect = QRect(r.x/_ratio+1, r.y/_ratio+1, r.width/_ratio+1, r.height/_ratio+1); tmpData.cvRect = r; tmpData.mat = croppedFace; cvtColor(croppedFace, tmpData.gray, CV_RGB2GRAY); // cv::resize( tmpData.gray, tmpData.gray, Size(WORK_SIZE,WORK_SIZE) ); detectorData << tmpData; } qRegisterMetaType< QList<struct DetectorData> >( "QList<struct DetectorData>" ); emit detectionFinished( _index, detectorData ); }
//! 显示最终生成的车牌图像,便于判断是否成功进行了旋转。 Mat CPlateLocate::showResultMat(Mat src, Size rect_size, Point2f center) { Mat img_crop; getRectSubPix(src, rect_size, center, img_crop); Mat resultResized; resultResized.create(HEIGHT, WIDTH, TYPE); resize(img_crop, resultResized, resultResized.size(), 0, 0, INTER_CUBIC); return resultResized; }
void LKTracker::normCrossCorrelation(const Mat& img1, const Mat& img2, vector<Point2f>& points1, vector<Point2f>& points2) { Mat rec0(10, 10, CV_8U); Mat rec1(10, 10, CV_8U); Mat res(1, 1, CV_32F); //double maxDis = 3.0f * sqrt(window_size.width*window_size.width + window_size.height*window_size.height); // 过滤距离过远的光流 similarity.clear(); for (int i = 0; i < points1.size(); i++) { if (status[i] == 1 /*&& norm(points1[i] - points2[i]) < maxDis*/) { getRectSubPix(img1, Size(10, 10), points1[i], rec0); getRectSubPix(img2, Size(10, 10), points2[i], rec1); matchTemplate(rec0, rec1, res, CV_TM_CCOEFF_NORMED); similarity.push_back( ((float *)(res.data))[0] ); } else { similarity.push_back(0.0); } } rec0.release(); rec1.release(); res.release(); }
Mat CControl::GetSubsetImg(RotatedRect n_rotatedrect) { // cout<<n_rotatedrect<<endl; //根据旋转矩形,从nimgraw中获得新图像。 //获得边界矩形。 Rect n_boundrect=n_rotatedrect.boundingRect(); //将边界在原图像上画出。 Point2f vertices[4]; n_rotatedrect.points(vertices); // Mat n_imgraw; // nImgRaw.copyTo(n_imgraw); // for (int i = 0; i < 4; i++) // line(n_imgraw, vertices[i], vertices[(i+1)%4], Scalar(0,255,0)); // imshow("raw",n_imgraw); //获得子图像。 Mat n_boundmatemp=nImgRaw(n_boundrect); Mat n_boundmat; n_boundmatemp.copyTo(n_boundmat); // imshow("prerotated",n_boundmat); //获得旋转变换参数矩阵 //这里的中心不再是原图像的中心,而是子图的中心。(原中心-左上角) Point2f n_pt1=n_rotatedrect.center; Point2f n_pt2=n_boundrect.tl(); Point2f n_ptcenter=n_pt1-n_pt2; Mat n_rotatematparam=getRotationMatrix2D(n_ptcenter,n_rotatedrect.angle,1.0); //进行仿射变换。 Mat n_rotatedMat; warpAffine(n_boundmat, n_rotatedMat,n_rotatematparam,n_boundmat.size(),INTER_CUBIC); //截取子图像。 Mat n_croppedmat; Size n_subsize(nControlOptions.nWidth,nControlOptions.nHeight); getRectSubPix(n_rotatedMat,n_subsize,n_ptcenter,n_croppedmat); // imshow("rotated",n_croppedmat); // waitKey(0); return n_croppedmat; }
void crop(Mat &segmentedHand, Mat &croppedHand) { // code taken from // http://stackoverflow.com/questions/3669611/bounding-box-using-opencv vector<vector<Point> > v; // Finds contours findContours(segmentedHand,v,CV_RETR_LIST,CV_CHAIN_APPROX_NONE); // Finds the contour with the largest area int area = 0; int idx; for(int i=0; i<v.size();i++) { if(area < v[i].size()) idx = i; } // Calculates the bounding rect of the largest area contour Rect rect = boundingRect(v[idx]); getRectSubPix( segmentedHand, rect.size(), Point2f(rect.x + rect.width/2.0, rect.y + rect.height/2.0), croppedHand); }
vector<Placa> RegionPlaca::segmento(Mat input){ vector<Placa> output;// creamos un array de clases de tipo Placa //Transformamos la imagen a escala de grises Mat img_gray; cvtColor(input, img_gray, CV_BGR2GRAY); blur(img_gray, img_gray, Size(5, 5)); //Para encontrar las lineas verticales de la placa, se debe resaltar las lineas Mat img_sobel; Sobel(img_gray, img_sobel, CV_8U, 1, 0, 3, 1, 0, BORDER_DEFAULT); if (showSteps) imshow("Sobel", img_sobel); //Se binariza la imagen Mat img_threshold; threshold(img_sobel, img_threshold, 0, 255, CV_THRESH_OTSU + CV_THRESH_BINARY); if (showSteps) imshow("Threshold", img_threshold); //Se hace un barrido de las lineas verticales y horizontales Mat element = getStructuringElement(MORPH_RECT, Size(20, 5)); morphologyEx(img_threshold, img_threshold, CV_MOP_CLOSE, element); if (showSteps) imshow("Close", img_threshold); //Encontramos todas las posibles regiones de placas de autos vector< vector< Point> > regiones; findContours(img_threshold, regiones, // Array de regiones CV_RETR_EXTERNAL, // retrieve the external contours CV_CHAIN_APPROX_NONE); // all pixels of each contours //Empezamos a analizar las regiones una por una vector<vector<Point> >::iterator itc = regiones.begin(); vector<RotatedRect> rects; // Rectangulos dentro de los limites indicados //Eliminamos las regiones que no se encuentran dentro de los limites permitidos. while (itc != regiones.end()) { //Create bounding rect of object RotatedRect angRect = minAreaRect(Mat(*itc)); if (!verificarTamaño(angRect, false)){ itc = regiones.erase(itc); } else{ ++itc; rects.push_back(angRect); } } // Pintamos de color azul las regiones que se encuentran dentro de los limites cv::Mat resultado; input.copyTo(resultado); // copiamos la imagen de entrada en la variable 'resultado' cv::drawContours(resultado, regiones, -1, // pintamos todos los contornos cv::Scalar(255, 0, 0), // asignamos que color 1, // Pintamos los contornos que encierran otros contornos 16);// Grosor de las lineas if (showSteps) imshow("ContornosAzul", resultado); for (int i = 0; i< rects.size(); i++){ std::string cadena = ""; cadena = static_cast<std::ostringstream*>(&(std::ostringstream() << i))->str(); //For better rect cropping for each posible box //Make floodfill algorithm because the plate has white background //And then we can retrieve more clearly the contour box circle(resultado, rects[i].center, 3, Scalar(0, 255, 0), -1); //get the min size between width and height float minSize = (rects[i].size.width < rects[i].size.height) ? rects[i].size.width : rects[i].size.height; minSize = minSize - minSize*0.5; //initialize rand and get 5 points around center for floodfill algorithm srand(time(NULL)); //Initialize floodfill parameters and variables Mat mask; mask.create(input.rows + 2, input.cols + 2, CV_8UC1); mask = Scalar::all(0); int loDiff = 30; int upDiff = 30; int connectivity = 4; int newMaskVal = 255; int NumSeeds = 10; Rect ccomp; int flags = connectivity + (newMaskVal << 8) + CV_FLOODFILL_FIXED_RANGE + CV_FLOODFILL_MASK_ONLY; for (int j = 0; j<NumSeeds; j++){ Point seed; seed.x = rects[i].center.x + rand() % (int)minSize - (minSize / 2); seed.y = rects[i].center.y + rand() % (int)minSize - (minSize / 2); circle(resultado, seed, 1, Scalar(0, 255, 255), -1); int area = floodFill(input, mask, seed, Scalar(255, 0, 0), &ccomp, Scalar(loDiff, loDiff, loDiff), Scalar(upDiff, upDiff, upDiff), flags); } if (showSteps) imshow("MASK" + cadena, mask); //cvWaitKey(0); //Check new floodfill mask match for a correct patch. //Get all points detected for get Minimal rotated Rect vector<Point> pointsInterest; Mat_<uchar>::iterator itMask = mask.begin<uchar>(); Mat_<uchar>::iterator end = mask.end<uchar>(); for (; itMask != end; ++itMask) if (*itMask == 255) pointsInterest.push_back(itMask.pos()); RotatedRect minRect = minAreaRect(pointsInterest); //imshow("Rotated minRECT" + cadena, result); if (verificarTamaño (minRect, true)){ // rotated rectangle drawing Point2f rect_points[4]; minRect.points(rect_points); for (int j = 0; j < 4; j++) line(resultado, rect_points[j], rect_points[(j + 1) % 4], Scalar(0, 0, 255), 1, 8); //imshow("Rotated mminRECT SEGUNDO" + cadena, result); //Get rotation matrix float r = (float)minRect.size.width / (float)minRect.size.height; float angle = minRect.angle; if (r<1) angle = 90 + angle; Mat rotmat = getRotationMatrix2D(minRect.center, angle, 1); //Create and rotate image Mat img_rotated; warpAffine(input, img_rotated, rotmat, input.size(), CV_INTER_CUBIC); //Se corta la imagen de la placa identificada Size rect_size = minRect.size; if (r < 1) swap(rect_size.width, rect_size.height); Mat img_crop; getRectSubPix(img_rotated, rect_size, minRect.center, img_crop); if (showSteps) imshow("imgCrop" + cadena, img_crop); Mat resultResized; resultResized.create(33, 144, CV_8UC3); resize(img_crop, resultResized, resultResized.size(), 0, 0, INTER_CUBIC); //Se convierte a escala de grises la imagen cortada Mat grayResult; cvtColor(resultResized, grayResult, CV_BGR2GRAY); blur(grayResult, grayResult, Size(3, 3)); grayResult = c1Bgr(grayResult); if (showSteps){ stringstream ss(stringstream::in | stringstream::out); ss << "tmp/" << nombreArchivo << "_" << i << ".jpg"; vector<int> compression_params; compression_params.push_back(CV_IMWRITE_PNG_COMPRESSION); compression_params.push_back(9); bool success = imwrite("C:/Users/gian/Documents/Visual Studio 2013/Projects/PlacaRNA/CaractSVM/" + ss.str(), grayResult, compression_params); if (success) cout << ss.str() << endl; } output.push_back(Placa(grayResult, minRect.boundingRect())); } } if (showSteps) imshow("Contours", resultado); return output; }
vector<Plate> DetectRegions::segment(Mat input){ vector<Plate> output; //convert image to gray Mat img_gray; //= *new Mat(input.size().width,input.size().height, CV_8UC1); cvtColor(input, img_gray, CV_BGR2GRAY); blur(img_gray, img_gray, Size(5,5)); //Finde vertical lines. Car plates have high density of vertical lines Mat img_sobel; Sobel(img_gray, img_sobel, CV_8U, 1, 0, 3, 1, 0, BORDER_DEFAULT); if(showSteps) imshow("Sobel", img_sobel); //threshold image Mat img_threshold; threshold(img_sobel, img_threshold, 0, 255, CV_THRESH_OTSU+CV_THRESH_BINARY); if(showSteps) imshow("Threshold", img_threshold); //Morphplogic operation close Mat element = getStructuringElement(MORPH_RECT, Size(17, 3) ); morphologyEx(img_threshold, img_threshold, CV_MOP_CLOSE, element); if(showSteps) imshow("Close", img_threshold); //Find contours of possibles plates vector< vector< Point> > contours; findContours(img_threshold, contours, // a vector of contours CV_RETR_EXTERNAL, // retrieve the external contours CV_CHAIN_APPROX_NONE); // all pixels of each contours //Start to iterate to each contour founded vector<vector<Point> >::iterator itc= contours.begin(); vector<RotatedRect> rects; //Remove patch that are no inside limits of aspect ratio and area. while (itc!=contours.end()) { //Create bounding rect of object RotatedRect mr= minAreaRect(Mat(*itc)); if( !verifySizes(mr)){ itc= contours.erase(itc); }else{ ++itc; rects.push_back(mr); } } // Draw blue contours on a white image cv::Mat result; input.copyTo(result); cv::drawContours(result,contours, -1, // draw all contours cv::Scalar(255,0,0), // in blue 1); // with a thickness of 1 for(int i=0; i< rects.size(); i++){ //For better rect cropping for each posible box //Make floodfill algorithm because the plate has white background //And then we can retrieve more clearly the contour box circle(result, rects[i].center, 3, Scalar(0,255,0), -1); //get the min size between width and height float minSize=(rects[i].size.width < rects[i].size.height)?rects[i].size.width:rects[i].size.height; minSize=minSize-minSize*0.5; //initialize rand and get 5 points around center for floodfill algorithm srand ( time(NULL) ); //Initialize floodfill parameters and variables Mat mask; mask.create(input.rows + 2, input.cols + 2, CV_8UC1); mask= Scalar::all(0); int loDiff = 30; int upDiff = 30; int connectivity = 4; int newMaskVal = 255; int NumSeeds = 10; Rect ccomp; int flags = connectivity + (newMaskVal << 8 ) + CV_FLOODFILL_FIXED_RANGE + CV_FLOODFILL_MASK_ONLY; for(int j=0; j<NumSeeds; j++){ Point seed; seed.x=rects[i].center.x+rand()%(int)minSize-(minSize/2); seed.y=rects[i].center.y+rand()%(int)minSize-(minSize/2); circle(result, seed, 1, Scalar(0,255,255), -1); int area = floodFill(input, mask, seed, Scalar(255,0,0), &ccomp, Scalar(loDiff, loDiff, loDiff), Scalar(upDiff, upDiff, upDiff), flags); } if(showSteps) imshow("MASK", mask); //cvWaitKey(0); //Check new floodfill mask match for a correct patch. //Get all points detected for get Minimal rotated Rect vector<Point> pointsInterest; Mat_<uchar>::iterator itMask= mask.begin<uchar>(); Mat_<uchar>::iterator end= mask.end<uchar>(); for( ; itMask!=end; ++itMask) if(*itMask==255) pointsInterest.push_back(itMask.pos()); RotatedRect minRect = minAreaRect(pointsInterest); if(verifySizes(minRect)){ // rotated rectangle drawing Point2f rect_points[4]; minRect.points( rect_points ); for( int j = 0; j < 4; j++ ) line( result, rect_points[j], rect_points[(j+1)%4], Scalar(0,0,255), 1, 8 ); //Get rotation matrix float r= (float)minRect.size.width / (float)minRect.size.height; float angle=minRect.angle; if(r<1) angle=90+angle; Mat rotmat= getRotationMatrix2D(minRect.center, angle,1); //Create and rotate image Mat img_rotated; warpAffine(input, img_rotated, rotmat, input.size(), CV_INTER_CUBIC); //Crop image Size rect_size=minRect.size; if(r < 1) swap(rect_size.width, rect_size.height); Mat img_crop; getRectSubPix(img_rotated, rect_size, minRect.center, img_crop); Mat resultResized; resultResized.create(33,144, CV_8UC3); resize(img_crop, resultResized, resultResized.size(), 0, 0, INTER_CUBIC); //Equalize croped image Mat grayResult; cvtColor(resultResized, grayResult, CV_BGR2GRAY); blur(grayResult, grayResult, Size(3,3)); grayResult=histeq(grayResult); if(saveRegions){ stringstream ss(stringstream::in | stringstream::out); ss << "tmp/" << filename << "_" << i << ".jpg"; imwrite(ss.str(), grayResult); } output.push_back(Plate(grayResult,minRect.boundingRect())); } } if(showSteps) imshow("Contours", result); return output; }
void cv::cornerSubPix( InputArray _image, InputOutputArray _corners, Size win, Size zeroZone, TermCriteria criteria ) { CV_INSTRUMENT_REGION() const int MAX_ITERS = 100; int win_w = win.width * 2 + 1, win_h = win.height * 2 + 1; int i, j, k; int max_iters = (criteria.type & CV_TERMCRIT_ITER) ? MIN(MAX(criteria.maxCount, 1), MAX_ITERS) : MAX_ITERS; double eps = (criteria.type & CV_TERMCRIT_EPS) ? MAX(criteria.epsilon, 0.) : 0; eps *= eps; // use square of error in comparsion operations cv::Mat src = _image.getMat(), cornersmat = _corners.getMat(); int count = cornersmat.checkVector(2, CV_32F); CV_Assert( count >= 0 ); Point2f* corners = cornersmat.ptr<Point2f>(); if( count == 0 ) return; CV_Assert( win.width > 0 && win.height > 0 ); CV_Assert( src.cols >= win.width*2 + 5 && src.rows >= win.height*2 + 5 ); CV_Assert( src.channels() == 1 ); Mat maskm(win_h, win_w, CV_32F), subpix_buf(win_h+2, win_w+2, CV_32F); float* mask = maskm.ptr<float>(); for( i = 0; i < win_h; i++ ) { float y = (float)(i - win.height)/win.height; float vy = std::exp(-y*y); for( j = 0; j < win_w; j++ ) { float x = (float)(j - win.width)/win.width; mask[i * win_w + j] = (float)(vy*std::exp(-x*x)); } } // make zero_zone if( zeroZone.width >= 0 && zeroZone.height >= 0 && zeroZone.width * 2 + 1 < win_w && zeroZone.height * 2 + 1 < win_h ) { for( i = win.height - zeroZone.height; i <= win.height + zeroZone.height; i++ ) { for( j = win.width - zeroZone.width; j <= win.width + zeroZone.width; j++ ) { mask[i * win_w + j] = 0; } } } // do optimization loop for all the points for( int pt_i = 0; pt_i < count; pt_i++ ) { Point2f cT = corners[pt_i], cI = cT; int iter = 0; double err = 0; do { Point2f cI2; double a = 0, b = 0, c = 0, bb1 = 0, bb2 = 0; getRectSubPix(src, Size(win_w+2, win_h+2), cI, subpix_buf, subpix_buf.type()); const float* subpix = &subpix_buf.at<float>(1,1); // process gradient for( i = 0, k = 0; i < win_h; i++, subpix += win_w + 2 ) { double py = i - win.height; for( j = 0; j < win_w; j++, k++ ) { double m = mask[k]; double tgx = subpix[j+1] - subpix[j-1]; double tgy = subpix[j+win_w+2] - subpix[j-win_w-2]; double gxx = tgx * tgx * m; double gxy = tgx * tgy * m; double gyy = tgy * tgy * m; double px = j - win.width; a += gxx; b += gxy; c += gyy; bb1 += gxx * px + gxy * py; bb2 += gxy * px + gyy * py; } } double det=a*c-b*b; if( fabs( det ) <= DBL_EPSILON*DBL_EPSILON ) break; // 2x2 matrix inversion double scale=1.0/det; cI2.x = (float)(cI.x + c*scale*bb1 - b*scale*bb2); cI2.y = (float)(cI.y - b*scale*bb1 + a*scale*bb2); err = (cI2.x - cI.x) * (cI2.x - cI.x) + (cI2.y - cI.y) * (cI2.y - cI.y); cI = cI2; if( cI.x < 0 || cI.x >= src.cols || cI.y < 0 || cI.y >= src.rows ) break; } while( ++iter < max_iters && err > eps ); // if new point is too far from initial, it means poor convergence. // leave initial point as the result if( fabs( cI.x - cT.x ) > win.width || fabs( cI.y - cT.y ) > win.height ) cI = cT; corners[pt_i] = cI; } }
void ELucidBinaryDescriptorExtractor::computeDescriptors( const cv::Mat& image, const std::vector<cv::KeyPoint>& key_points, std::vector<bool> *valid_descriptors, cv::Mat *descriptors) const { std::clock_t start = std::clock(); cv::Mat blurred_image; int _blur_radius = 5; //FIXME: move this to class member cv::blur(image, blurred_image, cv::Size(_blur_radius, _blur_radius)); const int num_channels = image.channels(); uchar pixels[num_samples]; valid_descriptors->reserve(key_points.size()); // TODO: Clean this up and don't use redundant code if(!_useWideDesc) { int desc_width = 32; assert(desc_width == num_samples / 2); cv::Mat descs(key_points.size(), desc_width, CV_8UC1); /* Unary Representation Lookup Tables*/ uchar lut_lower[4] = { 0x00, 0x01, 0x03, 0x07, }; uchar lut_upper[4] = { 0x00, 0x10, 0x30, 0x70, }; for(int k = 0; k < key_points.size(); ++k) { uchar *cur_desc = descs.ptr<uchar>(k); float x = key_points[k].pt.x; float y = key_points[k].pt.y; valid_descriptors->push_back( (x - patch_size/2) > 0 && (y - patch_size/2) > 0 && (x + patch_size/2) < image.cols && (y + patch_size/2) < image.rows); if((*valid_descriptors)[k]) { // TODO: Replace this by directly accessing pattern pixels cv::Mat patch; getRectSubPix(blurred_image, cv::Size(patch_size, patch_size), key_points[k].pt, patch); uchar* patch_ptr = patch.data; for(int p = 0; p < num_samples; ++p) { pixels[p] = patch_ptr[pattern[p][1] * patch_size + pattern[p][0]]; } int bin_width = 16; uchar temp_desc[num_samples]; Util::getRankVectors2(num_samples, bin_width, pixels, &(temp_desc[0])); int next_idx = 0; for(int i = 0; i < num_samples; i+=2) { cur_desc[next_idx++] = lut_lower[temp_desc[i]] | lut_upper[temp_desc[i+1]]; } } } std::clock_t stop = std::clock(); std::cout << "Time to compute eLUCID 256 bit descriptors " << (1000.0*(stop - start)) / CLOCKS_PER_SEC << "ms" << std::endl; *descriptors = descs; } else { int desc_width = 64; assert(desc_width == num_samples); cv::Mat descs(key_points.size(), desc_width, CV_8UC1); /* Sampled Unary Representation Lookup Tables*/ uchar lut[8] = { 0x00, 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f, }; for(int k = 0; k < key_points.size(); ++k) { uchar *cur_desc = descs.ptr<uchar>(k); float x = key_points[k].pt.x; float y = key_points[k].pt.y; valid_descriptors->push_back( (x - patch_size/2) > 0 && (y - patch_size/2) > 0 && (x + patch_size/2) < image.cols && (y + patch_size/2) < image.rows); if((*valid_descriptors)[k]) { // TODO: Replace this by directly accessing pattern pixels cv::Mat patch; getRectSubPix(blurred_image, cv::Size(patch_size, patch_size), key_points[k].pt, patch); uchar* patch_ptr = patch.data; for(int p = 0; p < num_samples; ++p) { pixels[p] = patch_ptr[pattern[p][1] * patch_size + pattern[p][0]]; } int bin_width = 8; uchar temp_desc[num_samples]; Util::getRankVectors2(num_samples, bin_width, pixels, &(temp_desc[0])); for(int i = 0; i < num_samples; i++) { cur_desc[i] = lut[temp_desc[i]]; } } } std::clock_t stop = std::clock(); std::cout << "Time to compute eLUCID 512 bit descriptors " << (1000.0*(stop - start)) / CLOCKS_PER_SEC << "ms" << std::endl; *descriptors = descs; } }
double getSubpix(const Mat& img, Point2f pt) { Mat patch; getRectSubPix(img, cv::Size(1,1), pt, patch); return patch.at<int>(0,0); }
void DetectRegions::part2( const cv::Mat& input, std::vector<img_Plate>& output, cv::Mat& img_threshold, const std::string& out_id ) { cv::Mat my_input; input.copyTo(my_input); //Find contours of possibles plates std::vector< std::vector< cv::Point> > contours; findContours( img_threshold, contours, // a vector of contours CV_RETR_EXTERNAL, // retrieve the external contours // CV_CHAIN_APPROX_NONE ); // all pixels of each contours CV_CHAIN_APPROX_SIMPLE ); //Start to iterate to each contour founded std::vector< std::vector<cv::Point> >::iterator itc = contours.begin(); std::vector<cv::RotatedRect> rects; cv::Mat my_input_rect; input.copyTo(my_input_rect); //Remove patch that are no inside limits of aspect ratio and area. while (itc != contours.end()) { //Create bounding rect of object cv::RotatedRect mr = minAreaRect(cv::Mat(*itc)); if (!verifySizes(mr)) { itc = contours.erase(itc); // rotated rectangle drawing cv::Point2f rect_points[4]; mr.points( rect_points ); for (int j = 0; j < 4; ++j) line( my_input_rect, rect_points[j], rect_points[ (j + 1) % 4 ], cv::Scalar(255,0,0), 1, 8 ); } else { ++itc; rects.push_back(mr); // rotated rectangle drawing cv::Point2f rect_points[4]; mr.points( rect_points ); for (int j = 0; j < 4; ++j) line( my_input_rect, rect_points[j], rect_points[ (j + 1) % 4 ], cv::Scalar(0,255,0), 2, 8 ); } } D_IMG_SAVE( my_input_rect, "img_" << out_id << "Rect.png" ); // Draw blue contours on a white image cv::Mat result; input.copyTo(result); cv::drawContours( result, contours, -1, // draw all contours cv::Scalar(255,0,0), // in blue 1 ); // with a thickness of 1 // 3 ); // with a thickness of 1 D_IMG_SAVE( result, "04_img_" << out_id << "Contours.png" ); // std::cerr << "rects.size : " << rects.size() << std::endl; std::vector<cv::Mat> Mats; for (unsigned int i = 0; i < rects.size(); ++i) { //For better rect cropping for each posible box //Make floodfill algorithm because the plate has white background //And then we can retrieve more clearly the contour box circle(result, rects[i].center, 3, cv::Scalar(0,255,0), -1); //get the min size between width and height // float minSize = ( (rects[i].size.width < rects[i].size.height) float minSize = ( (rects[i].size.width > rects[i].size.height) ? (rects[i].size.width) : (rects[i].size.height) ); minSize = minSize - minSize * 0.5; //initialize rand and get 5 points around center for floodfill algorithm srand ( time(NULL) ); //Initialize floodfill parameters and variables cv::Mat mask; mask.create(input.rows + 2, input.cols + 2, CV_8UC1); mask = cv::Scalar::all(0); int loDiff = 30; int upDiff = 30; int connectivity = 4; int newMaskVal = 255; // int NumSeeds = 100; cv::Rect ccomp; int flags = connectivity + (newMaskVal << 8) + CV_FLOODFILL_FIXED_RANGE + CV_FLOODFILL_MASK_ONLY; int max_size = rects[i].size.width * rects[i].size.height; cv::Rect b_rect = rects[i].boundingRect(); int min_x = b_rect.x; int min_y = b_rect.y; int max_x = min_x + b_rect.width; int max_y = min_y + b_rect.height; for (int local_y = min_y; local_y < max_y; local_y += 5) for (int local_x = min_x; local_x < max_x; local_x += 5) { cv::Point seed; seed.x = local_x; seed.y = local_y; if (Collision( contours[i], seed )) { cv::Mat tmp_mask; tmp_mask.create( input.rows + 2, input.cols + 2, CV_8UC1 ); tmp_mask = cv::Scalar::all(0); int area = floodFill( input, tmp_mask, seed, cv::Scalar(255,0,0), &ccomp, cv::Scalar(loDiff, loDiff, loDiff), cv::Scalar(upDiff, upDiff, upDiff), flags ); { cv::Point c( ccomp.x + ccomp.width / 2, ccomp.y + ccomp.height / 2 ); cv::Size s( ccomp.width, ccomp.height ); cv::RotatedRect tmp_rect( c, s, 0 ); // rotated rectangle drawing cv::Point2f rect_points[4]; tmp_rect.points( rect_points ); for (int j = 0; j < 4; ++j) line( my_input, rect_points[j], rect_points[ (j + 1) % 4 ], cv::Scalar(0,255,255), 1, 8 ); } bool rect_invalid = ( ccomp.x < min_x || ccomp.x > max_x || ccomp.y < min_y || ccomp.y > max_y ); cv::Point left_top( min_x, min_y ); cv::Point right_top( max_x, min_y ); cv::Point left_bottom( min_x, max_y ); cv::Point right_bottom( max_x, max_y ); if (area > max_size) { circle( result, seed, 1, cv::Scalar(255,0,0), -1 ); circle( my_input, seed, 1, cv::Scalar(255,0,0), -1 ); } else if (rect_invalid) { circle( result, seed, 1, cv::Scalar(255,0,0), -1 ); circle( my_input, seed, 1, cv::Scalar(255,0,0), -1 ); } else { circle( result, seed, 1, cv::Scalar(0,255,0), -1 ); circle( my_input, seed, 1, cv::Scalar(0,255,0), -1 ); floodFill( input, mask, seed, cv::Scalar(255,0,0), &ccomp, cv::Scalar(loDiff, loDiff, loDiff), cv::Scalar(upDiff, upDiff, upDiff), flags ); } } else { circle( result, seed, 1, cv::Scalar(255,0,0), -1 ); circle( my_input, seed, 1, cv::Scalar(255,0,0), -1 ); } } // for (int j = 0; j < NumSeeds; ++j) { // rotated rectangle drawing cv::Point2f rect_points[4]; rects[i].points( rect_points ); for (int j = 0; j < 4; ++j) line( my_input, rect_points[j], rect_points[ (j + 1) % 4 ], cv::Scalar(255,255,255), 2, 8 ); D_IMG_SAVE( mask, "img_" << out_id << "" << i << "_01_Mask.png" ); } //cvWaitKey(0); //Check new floodfill mask match for a correct patch. //Get all points detected for get Minimal rotated Rect std::vector<cv::Point> pointsInterest; cv::Mat_<uchar>::iterator itMask = mask.begin<uchar>(); cv::Mat_<uchar>::iterator end = mask.end<uchar>(); for (; itMask != end; ++itMask) if (*itMask == 255) pointsInterest.push_back(itMask.pos()); if (pointsInterest.size() < 2) continue; cv::RotatedRect minRect = minAreaRect(pointsInterest); if (verifySizes(minRect)) { // rotated rectangle drawing cv::Point2f rect_points[4]; minRect.points( rect_points ); for( int j = 0; j < 4; j++ ) line( result, rect_points[j], rect_points[(j+1)%4], cv::Scalar(0,0,255), 1, 8 ); //Get rotation matrix float r = (float)minRect.size.width / (float)minRect.size.height; float angle=minRect.angle; if (r < 1) angle = 90 + angle; cv::Mat rotmat = getRotationMatrix2D(minRect.center, angle,1); //Create and rotate image cv::Mat img_rotated; warpAffine(input, img_rotated, rotmat, input.size(), CV_INTER_CUBIC); //Crop image cv::Size rect_size = minRect.size; if (r < 1) std::swap( rect_size.width, rect_size.height ); cv::Mat img_crop; getRectSubPix(img_rotated, rect_size, minRect.center, img_crop); D_IMG_SAVE( img_crop, "img_" << out_id << "" << i << "_02_crop.png" ); cv::Mat resultResized; resultResized.create(33,144, CV_8UC3); resize(img_crop, resultResized, resultResized.size(), 0, 0, cv::INTER_CUBIC); D_IMG_SAVE( resultResized, "img_" << out_id << "" << i << "_03_resultResized.png" ); output.push_back( img_Plate( resultResized, minRect.boundingRect() ) ); // //Equalize croped image // cv::Mat grayResult; // cvtColor(resultResized, grayResult, CV_BGR2GRAY); // // blur(grayResult, grayResult, Size(3,3)); // grayResult = histeq(grayResult); // D_IMG_SAVE( grayResult, "img_" << out_id << "" << i << "_04_grayResult.png" ); // output.push_back( Plate( grayResult, minRect.boundingRect() ) ); } // if (verifySizes(minRect)) } // for (int i = 0; i < rects.size(); ++i) D_IMG_SAVE( result, "10_img_" << out_id << "Contours.png" ); D_IMG_SAVE( my_input, "11_img_" << out_id << "my_input.png" ); }
int parting_char(Mat &img) { int nRows; int nCols; int nCnt; int sum; int avg; int start; Mat img_clip; if(img.channels() != 1) { printf("parting_char(Mat &img) channel is not 1\n"); return -1; } nRows = img.rows; nCols = img.cols; int *h_Cnt = new int[nCols]; memset(h_Cnt,0,sizeof(int)*nCols); for(int j=0;j<nCols;++j) { for(int i=0;i<nRows;++i) { if(img.at<uchar>(i,j) != 0x0) ++h_Cnt[j]; } } //getRectSubPix(img,Size(img.width,),Point(img_rect.cols/2,up+(down-up)/2),img_clip); for(int i =0;i<nCols;++i) { if(h_Cnt[i] != 0) { // printf("i=%d,value=%d",i,h_Cnt[i]); start = i; nCnt = 0; while(i<nCols&&h_Cnt[i] != 0) { ++nCnt; ++i; } sum = 0; for(int j =0;j<nCnt;++j) { sum += h_Cnt[i+j]; } avg = sum / nCnt; if(avg >= 3) { printf("start=%d,end=%d\n",start,i); getRectSubPix(img,Size(i-start,img.rows),Point(start+(i-start)/2,img.rows/2),img_clip); string str = "abc"+i; namedWindow(str,CV_WINDOW_NORMAL); imshow(str,img_clip); } } } delete h_Cnt; return 0; }
int main(int argc,char**argv) { int scale = 1; int delta = 0; int ddepth = CV_16S; // check the number of parameter if(argc !=2) { printf("please follow like this\n"); printf("exe[] img_name\n"); return -1; } // reads image img_src = imread(argv[1]); // check whether read operation is ok or not if(img_src.data == NULL) { printf("could not open or find the image!\n"); return -1; } // use Gaussian blur to reduce the noise GaussianBlur(img_src,img_src,Size(3,3),0,0,BORDER_DEFAULT); // convert source image to gray image cvtColor(img_src,img_gray,CV_BGR2GRAY); // sobel in x direction Sobel(img_gray,grad_x,ddepth,1,0,3,scale,delta,BORDER_DEFAULT); convertScaleAbs(grad_x,abs_grad_x); // use sobel in y direction Sobel(img_gray,grad_y,ddepth,0,1,3,scale,delta,BORDER_DEFAULT); convertScaleAbs(grad_y,abs_grad_y); // add weight,and addWeighted(abs_grad_x,0.5,abs_grad_y,0.5,0,grad); // use threshold to binarition and threshold select use the OTSU method threshold(grad,img_bin_thre,0,255,THRESH_BINARY|THRESH_OTSU); // first Dilate,second erode Mat element = getStructuringElement(MORPH_RECT,Size(2*1+1,2*1+1),Point(-1,-1)); for(int i = 0;i < 3; i++) { morphologyEx(img_bin_thre,img_bin_thre,MORPH_OPEN,element); morphologyEx(img_bin_thre,img_bin_thre,MORPH_CLOSE,element); } // origin method ,this is worse than morphologyEx // dilate(img_bin_thre,img_bin_thre,element); // namedWindow("dilated",CV_WINDOW_NORMAL); // imshow("dilated",img_bin_thre); // erode(img_bin_thre,img_bin_thre,element); // namedWindow("erode",CV_WINDOW_NORMAL); // imshow("erode",img_bin_thre); // find contour,in here must use the binarition image // define vector<Vec4i> hierarchy; vector< vector<Point> >contours; // use function findContours(img_bin_thre,contours,hierarchy,CV_RETR_CCOMP,CV_CHAIN_APPROX_SIMPLE,Point(0,0)); // please change min and the max area value based on reality int min_area = 100000; int max_area = 300000; Rect mRect; int tempArea; // define the color drawing contour Scalar color = Scalar(255,255,0); Mat drawing = Mat::zeros(img_bin_thre.size(),CV_8UC1); for(int i = 0;i < contours.size();i++) { // get the minimum rectangle of the contours mRect = boundingRect(contours[i]); // computer the square of mRect tempArea = mRect.height * mRect.width; // for debug // printf("tempArea.height:%d\ttempArea.width:%d\ttempArea.area=%d\n",mRect.height,mRect.width,tempArea); // filter area which meet the requirement if(((double)mRect.width/(double)mRect.height) > 2.0 && (tempArea > min_area) && ((double)mRect.width/(double)mRect.height < 4) && (tempArea < max_area)) // draw contours { drawContours(drawing,contours,i,color,2,8,hierarchy); // here use 2 image ,one is just from image which be processed by threshold,the other is the original gray image,if you just use first,you // may not getRectSubPix(img_bin_thre,Size(mRect.width,mRect.height),Point(mRect.x+mRect.width/2,mRect.y\ +mRect.height/2),img_get_rect); getRectSubPix(img_gray,Size(mRect.width,mRect.height),Point(mRect.x+mRect.width/2,mRect.y\ +mRect.height/2),img_get_rect_new); } } if(img_get_rect.data == NULL) { printf("img_get rect is null\n"); return -1; } if(img_get_rect_new.data == NULL) { printf("img_get_rect_new is null!\n"); return -1; } // use the HoughLinesP // define lines vector<Vec4i> lines; // Mat color_dst; // img_lines = img_get_rect.clone(); cvtColor(img_get_rect,img_lines,CV_GRAY2BGR); // check the line in image img_get_rect HoughLinesP(img_get_rect,lines,1,CV_PI/180,200,200,10); printf("lines.size()=%d\n",lines.size()); int distance = 0; // int theta; double temp_slope = 0,slope; int res_x1,res_y1,res_x2,res_y2; // define map vector for computer the line used frequency // vector <int,int> ivect;//first is the number of this line , next is the longest distance // map <double,ivect> imap; int delta_x,delta_y; std::vector <dou_int> ivec; std::vector <dou_int>::iterator iter; for(size_t i = 0;i < lines.size();i++) { Vec4i l = lines[i]; line(img_lines,Point(l[0],l[1]),Point(l[2],l[3]),Scalar(0,0,255),3); // find tilt angle if(l[2]-l[0] == 0) ; else { // computer this line 's slope // delta_x / delta_y delta_y = (l[3]-l[1]); delta_x = (l[2]-l[0]); distance = delta_y*delta_y+delta_x*delta_x; temp_slope = ((double)delta_y)/((double)(delta_x)); printf("in i=%d,delta_y=%d,delta_x=%d\n",i,delta_y,delta_x); for(iter = ivec.begin();iter != ivec.end();iter++) { // if in one line,num++,update the max length if(abs(iter->slope - temp_slope) < (double)0.01) { iter->num++; if(iter->maxlength < distance) { iter->maxlength = distance; iter->v0 = Point(l[0],l[1]); iter->v1 = Point(l[2],l[3]); } break; } } // not find this slope ,must add it by hand if(iter == ivec.end()) { ivec.push_back(dou_int(temp_slope,distance,1,Point(l[0],l[1]),Point(l[2],l[3]))); } } } int max = 0; int j = 0; int index = 0; dou_int res; for(j=0,iter = ivec.begin();iter != ivec.end();j++,iter++) { if(iter->num > max) { max = iter->num; index = j; } } printf("index is %d\n",index); for(j=0,iter = ivec.begin();iter != ivec.end() && j <= index;j++,iter++) { if(j == index) { res = dou_int(iter->slope,iter->maxlength,iter->num,iter->v0,iter->v1); printf("slope is %f\n",iter->slope); break; } } // drawing the tilt line line(img_lines,res.v0,res.v1,Scalar(255,255,0),1); Mat img_lines_out; Point center = Point(img_lines.cols/2,img_lines.rows/2); double angle =(double)(180/CV_PI)*(double)atan(res.slope); printf("angle is :%f\n",angle); Mat rot_mat = getRotationMatrix2D(center,angle,1.0); warpAffine(img_lines,img_lines_out,rot_mat,img_lines.size()); Mat img_rect; warpAffine(img_get_rect_new,img_rect,rot_mat,img_get_rect_new.size()); cvtColor(img_lines_out,img_lines_out,CV_BGR2GRAY); printf("img_clip's channel is:%d\n",img_lines_out.channels()); threshold(img_lines_out,img_lines_out,10,255,THRESH_BINARY | THRESH_OTSU); Mat img_clip; int up,down; if(-1 != remove_Border_Vertical(img_lines_out,up,down)) { printf("up=%d,down=%d\n",up,down); getRectSubPix(img_lines_out,Size(img_lines_out.cols,down-up),Point(img_lines_out.cols/2,up+(down-up)/2),img_clip); namedWindow("line_clip",CV_WINDOW_NORMAL); imshow("line_clip",img_clip); getRectSubPix(img_rect,Size(img_rect.cols,down-up),Point(img_rect.cols/2,up+(down-up)/2),img_clip); namedWindow("new_clip",CV_WINDOW_NORMAL); imshow("new_clip",img_clip); } // binarition OTSU threshold(img_clip,img_clip,10,255,THRESH_BINARY | THRESH_OTSU); namedWindow("newrect",CV_WINDOW_NORMAL); imshow("newrect",img_clip); parting_char(img_clip); waitKey(0); return 0; }
void ModelMaker::extractModel(cv::Mat origframe) { // qDebug()<<"Frame is"<<frame.empty(); for(int i = 0; i < centroids.size(); i++) { Mat subtractedframe(origframe); subtractedframe = subtractBack(origframe); Mat polymask = subtractedframe.clone(); // cv::cvtColor(frameMat, frameMat, CV_BGR2BGRA); // cv::cvtColor(polymask, polymask, CV_BGR2BGRA); //cv::rectangle(mask, Point( 0, 0 ), Point( mask.cols, mask.rows), Scalar( 0, 255,0,255 ),-1, 8 ); //Fill all mask in polymask.setTo(Scalar(0,0,0,0)); //Polgon Masking polygon = paintCanvas->polygons.at(i); Point poly_points[polygon.size()]; //Find point furthest from center Point furthest = Point(paintCanvas->centerPoint.x()*xscale,paintCanvas->centerPoint.y()*yscale); //set to center int scaledcenterx = paintCanvas->centerPoint.x()*xscale; int scaledcentery = paintCanvas->centerPoint.y()*yscale; int scaledheadx= paintCanvas->headPoint.x()*xscale; int scaledheady=paintCanvas->headPoint.y()*yscale; float biggestdistancesquared=0; for(int j=0;j<polygon.size();j++) { poly_points[j]=Point(xscale*polygon.at(j).x(), yscale*polygon.at(j).y()); Point candidate = Point(xscale*polygon.at(j).x(), yscale*polygon.at(j).y()); float distancecandidatesquared; //Find furthest distancecandidatesquared= (candidate.x - scaledcenterx)*(candidate.x - scaledcenterx) + (candidate.y - scaledcentery)*(candidate.y - scaledcentery); if(distancecandidatesquared>biggestdistancesquared){ biggestdistancesquared=distancecandidatesquared; qDebug()<<"biggcandidate x "<<candidate.x <<" y "<<candidate.y << " distance ="<<biggestdistancesquared; } } const Point* ppt[1] = { poly_points }; int npt[] = { polygon.size() }; fillPoly( polymask, ppt, npt, 1, Scalar( 255, 255,255,255 ), 8, 0); //Debug // cv::circle(origframe,cv::Point(scaledcenterx,scaledcentery),1,Scalar(255,255,255,255),2); // cv::circle(origframe,cv::Point(scaledheadx,scaledheady),1,Scalar(255,0,255, 254),2); //cv::circle(polymask,cv::Point(scaledcenterx,scaledcentery),1,Scalar(255,255,255,255),2); // cv::circle(polymask,cv::Point(scaledheadx,scaledheady),1,Scalar(255,0,255, 254),2); // cv::circle(subtractedframe,cv::Point(scaledcenterx,scaledcentery),1,Scalar(255,255,255,255),2); // cv::circle(subtractedframe,cv::Point(scaledheadx,scaledheady),1,Scalar(255,0,255, 254),2); //background subtraction: take original image, apply background as a mask, save over original //bitwise_and(subtractedframe, polymask, subtractedframe); qDebug()<<"Roi "<<x1<<" "<<y1<<" "<<x2<<" "<<y2<<" "; cv::cvtColor(polymask,polymask, CV_RGB2GRAY); //Full alpha mask = polygon selection (a =200) + BG subtracted organism (a= 255) + Center Mark ( a = 250) + head mark (a = 240) //Set Head to alpha=240 //Set Center to Alpha = 250 //Everything inside mask == alpha 200 //Everything outside alpha=100; //BG subtracted ant = 255 Mat maskedsubtraction; subtractedframe.copyTo(maskedsubtraction,polymask); // note that m.copyTo(m,mask) will have no masking effect cvtColor(maskedsubtraction, maskedsubtraction,CV_BGR2GRAY); polymask = polymask+155; //255 moves to 255, 0 moves to 155 polymask = polymask - 55; //255 moves to 200, 155 moves to 100 maskedsubtraction = polymask+maskedsubtraction; cv::circle(maskedsubtraction,cv::Point(scaledcenterx,scaledcentery),1,Scalar(250),2); //Encode the Center cv::circle(maskedsubtraction,cv::Point(scaledheadx,scaledheady),1,Scalar(240),2); //encode the head Mat bgr; bgr=origframe.clone(); Mat alpha; maskedsubtraction.copyTo(alpha); Mat bgra; cvtColor(origframe, bgra,CV_BGR2BGRA); //Copy the origframe, we'll write over it next // forming array of matrices is quite efficient operations, // because the matrix data is not copied, only the headers Mat in[] = { bgr, alpha }; // BGRa[0] -> bgr[0], BGRa[1] -> bgr[1], // BGRa[2] -> bgr[2], BGRa[3] -> alpha[0] int from_to[] = { 0,0, 1,1, 2,2, 3,3 }; mixChannels( in, 2, &bgra, 1, from_to, 4 ); // input array, number of files in input array, destination, number of files in destination, from-to array, number of pairs in from-to QString ext = ".png"; // QString fullframe = savepath+paintCanvas->polyNames.at(i)+"_"+QString::number(centroids[i].x())+"_"+QString::number(centroids[i].y())+"_"+QString::number(currentFrame)+ext; QString modelfilename = savepath+paintCanvas->polyNames.at(i)+"_f"+QString::number(currentFrame)+ext; //DEBUG IMAGES /* imwrite(modelfilename.toStdString()+"_subtraction",subtractedframe); imwrite(modelfilename.toStdString()+"_polymask",polymask); imwrite(modelfilename.toStdString()+"_alpha",alpha); */ //save out Model //Full Keyframe // imwrite(modelfilename.toStdString()+"_keyframe",bgra); //Disabled for now qDebug()<<"Saved out: "<<modelfilename; //***Crop and Rotate ***// qDebug()<<"crop centered on "<<scaledcenterx<<" "<<scaledcentery; //crop the frame based on ROI Point2f src_center(scaledcenterx, scaledcentery); //To do this correctly use getRectSubPix instead of frameMat(MYROI) method // getRectSubPix only works with certain image formats (this is undocumented in opencv : P // so we have to do that cutting and mixing again! getRectSubPix(bgr, cv::Size(sqrt(biggestdistancesquared)*2,sqrt(biggestdistancesquared)*2), src_center, bgr); getRectSubPix(alpha, cv::Size(sqrt(biggestdistancesquared)*2,sqrt(biggestdistancesquared)*2), src_center, alpha); Mat bgracropped; cvtColor(bgr, bgracropped,CV_BGR2BGRA); //Copy the origframe, we'll write over it next Mat inagain[] = { bgr, alpha }; int from_to2[] = { 0,0, 1,1, 2,2, 3,3 }; //Note: the height and width dimensions have to be the same for the inputs and outputs mixChannels( inagain, 2, &bgracropped, 1, from_to2, 4 ); // input array, number of files in input array, destination, number of files in destination, from-to array, number of pairs in from-to //rotate the cropped frame about the center of the cropped frame. qDebug()<<"Rotate that image "<<angle; bgracropped = rotateImage(bgracropped, angle);//Rotate full image about this center //after I rotate clear the global angle angle =0; //debug angle=-1; // Save the Nicely Rotated and Cropped Model File imwrite(modelfilename.toStdString(),bgracropped); centroids.clear(); maxXY.clear(); minXY.clear(); paintCanvas->polyNames.clear(); paintCanvas->polygons.clear(); paintCanvas->masks.pop_back(); polyinfo = "Polygon cleared"; paintCanvas->temp.clear(); ui->statusBar->showMessage(polyinfo,2000); paintCanvas->replyMask = replyNull; capture.set(CV_CAP_PROP_POS_FRAMES,(double)currentFrame); } }
vector<PlateRegion> DetectorMorph::detect(Mat frame, std::vector<cv::Rect> regionsOfInterest) { Mat frame_gray,frame_gray_cp; if (frame.channels() > 2) { cvtColor( frame, frame_gray, CV_BGR2GRAY ); } else { frame.copyTo(frame_gray); } frame_gray.copyTo(frame_gray_cp); blur(frame_gray, frame_gray, Size(5, 5)); vector<PlateRegion> detectedRegions; for (int i = 0; i < regionsOfInterest.size(); i++) { Mat img_open, img_result; Mat element = getStructuringElement(MORPH_RECT, Size(30, 4)); morphologyEx(frame_gray, img_open, CV_MOP_OPEN, element, cv::Point(-1, -1)); img_result = frame_gray - img_open; if (config->debugDetector && config->debugShowImages) { imshow("Opening", img_result); } //threshold image using otsu thresholding Mat img_threshold, img_open2; threshold(img_result, img_threshold, 0, 255, CV_THRESH_OTSU + CV_THRESH_BINARY); if (config->debugDetector && config->debugShowImages) { imshow("Threshold Detector", img_threshold); } Mat diamond(5, 5, CV_8U, cv::Scalar(1)); diamond.at<uchar>(0, 0) = 0; diamond.at<uchar>(0, 1) = 0; diamond.at<uchar>(1, 0) = 0; diamond.at<uchar>(4, 4) = 0; diamond.at<uchar>(3, 4) = 0; diamond.at<uchar>(4, 3) = 0; diamond.at<uchar>(4, 0) = 0; diamond.at<uchar>(4, 1) = 0; diamond.at<uchar>(3, 0) = 0; diamond.at<uchar>(0, 4) = 0; diamond.at<uchar>(0, 3) = 0; diamond.at<uchar>(1, 4) = 0; morphologyEx(img_threshold, img_open2, CV_MOP_OPEN, diamond, cv::Point(-1, -1)); Mat rectElement = getStructuringElement(cv::MORPH_RECT, Size(13, 4)); morphologyEx(img_open2, img_threshold, CV_MOP_CLOSE, rectElement, cv::Point(-1, -1)); if (config->debugDetector && config->debugShowImages) { imshow("Close", img_threshold); waitKey(0); } //Find contours of possibles plates vector< vector< Point> > contours; findContours(img_threshold, contours, // a vector of contours CV_RETR_EXTERNAL, // retrieve the external contours CV_CHAIN_APPROX_NONE); // all pixels of each contours //Start to iterate to each contour founded vector<vector<Point> >::iterator itc = contours.begin(); vector<RotatedRect> rects; //Remove patch that are no inside limits of aspect ratio and area. while (itc != contours.end()) { //Create bounding rect of object RotatedRect mr = minAreaRect(Mat(*itc)); if (mr.angle < -45.) { mr.angle += 90.0; swap(mr.size.width, mr.size.height); } if (!CheckSizes(mr)) itc = contours.erase(itc); else { ++itc; rects.push_back(mr); } } //Now prunning based on checking all candidate plates for a min/max number of blobsc Mat img_crop, img_crop_b, img_crop_th, img_crop_th_inv; vector< vector< Point> > plateBlobs; vector< vector< Point> > plateBlobsInv; double thresholds[] = { 10, 40, 80, 120, 160, 200, 240 }; const int num_thresholds = 7; int numValidChars = 0; Mat rotated; for (int i = 0; i < rects.size(); i++) { numValidChars = 0; RotatedRect PlateRect = rects[i]; Size rect_size = PlateRect.size; // get the rotation matrix Mat M = getRotationMatrix2D(PlateRect.center, PlateRect.angle, 1.0); // perform the affine transformation warpAffine(frame_gray_cp, rotated, M, frame_gray_cp.size(), INTER_CUBIC); //Crop area around candidate plate getRectSubPix(rotated, rect_size, PlateRect.center, img_crop); if (config->debugDetector && config->debugShowImages) { imshow("Tilt Correction", img_crop); waitKey(0); } for (int z = 0; z < num_thresholds; z++) { cv::threshold(img_crop, img_crop_th, thresholds[z], 255, cv::THRESH_BINARY); cv::threshold(img_crop, img_crop_th_inv, thresholds[z], 255, cv::THRESH_BINARY_INV); findContours(img_crop_th, plateBlobs, // a vector of contours CV_RETR_LIST, // retrieve the contour list CV_CHAIN_APPROX_NONE); // all pixels of each contours findContours(img_crop_th_inv, plateBlobsInv, // a vector of contours CV_RETR_LIST, // retrieve the contour list CV_CHAIN_APPROX_NONE); // all pixels of each contours int numBlobs = plateBlobs.size(); int numBlobsInv = plateBlobsInv.size(); float idealAspect = config->avgCharWidthMM / config->avgCharHeightMM; for (int j = 0; j < numBlobs; j++) { cv::Rect r0 = cv::boundingRect(cv::Mat(plateBlobs[j])); if (ValidateCharAspect(r0, idealAspect)) numValidChars++; } for (int j = 0; j < numBlobsInv; j++) { cv::Rect r0 = cv::boundingRect(cv::Mat(plateBlobsInv[j])); if (ValidateCharAspect(r0, idealAspect)) numValidChars++; } } //If too much or too lcittle might not be a true plate //if (numBlobs < 3 || numBlobs > 50) continue; if (numValidChars < 4 || numValidChars > 50) continue; PlateRegion PlateReg; // Ensure that the rectangle isn't < 0 or > maxWidth/Height Rect bounding_rect = PlateRect.boundingRect(); PlateReg.rect = expandRect(bounding_rect, 0, 0, frame.cols, frame.rows); detectedRegions.push_back(PlateReg); } } return detectedRegions; }