float Index::getKeyPointOrientation(const Mat& image, const KeyPoint &pnt) { int half_k = ROTATION_PATCH_SIZE/2; Point2f pt = pnt.pt; int m_01 = 0, m_10 = 0; const uchar* center = image.ptr<uchar> (cvRound(pt.y), cvRound(pt.x)); // Treat the center line differently, v=0 for (int u = -half_k; u <= half_k; ++u) m_10 += u * center[u]; // Go line by line in the circular patch int step = (int)image.step1(); for (int v = 1; v <= half_k; ++v) { // Proceed over the two lines int v_sum = 0; int d = u_max[v]; for (int u = -d; u <= d; ++u) { int val_plus = center[u + v*step], val_minus = center[u - v*step]; v_sum += (val_plus - val_minus); m_10 += u * (val_plus + val_minus); } m_01 += v * v_sum; } return fastAtan2((float)m_01, (float)m_10); }
float IC_Angle(const Mat& image, const int half_k, Point2f pt, const vector<int> & u_max) { int m_01 = 0, m_10 = 0; const uchar* center = &image.at<uchar> (cvRound(pt.y), cvRound(pt.x)); // Treat the center line differently, v=0 for (int u = -half_k; u <= half_k; ++u) m_10 += u * center[u]; // Go line by line in the circular patch int step = (int)image.step1(); for (int v = 1; v <= half_k; ++v) { // Proceed over the two lines int v_sum = 0; int d = u_max[v]; for (int u = -d; u <= d; ++u) { int val_plus = center[u + v*step], val_minus = center[u - v*step]; v_sum += (val_plus - val_minus); m_10 += u * (val_plus + val_minus); } m_01 += v * v_sum; } return fastAtan2((float)m_01, (float)m_10); }
/*step的方式遍历*/ void sharpen2(const Mat &image, Mat &result) { result.create(image.size(), image.type()); // allocate if necessary int step= image.step1(); const uchar* previous= image.data; // ptr to previous row const uchar* current= image.data+step; // ptr to current row const uchar* next= image.data+2*step; // ptr to next row uchar *output= result.data+step; // ptr to output row for (int j= 1; j<image.rows-1; j++) { // for each row (except first and last) for (int i=1; i<image.cols-1; i++) { // for each column (except first and last) output[i]= saturate_cast<uchar>(5*current[i]-current[i-1]-current[i+1]-previous[i]-next[i]); } previous+= step; current+= step; next+= step; output+= step; } // Set the unprocess pixels to 0 result.row(0).setTo(cv::Scalar(0)); result.row(result.rows-1).setTo(cv::Scalar(0)); result.col(0).setTo(cv::Scalar(0)); result.col(result.cols-1).setTo(cv::Scalar(0)); }
string OCR::getText(Mat src, Rect mask) { if (!src.data) { cerr << "getText: No image data!" << endl; return string(""); } // tesseract::TessBaseAPI *api = new tesseract::TessBaseAPI(); // if (api -> Init(NULL, "eng2+fra+ita+deu")) // { // fprintf(stderr, "Could not initialize tesseract.\n"); // exit(-1); // } Mat dst; preprocess(src, dst, mask); api -> SetImage((uchar*)dst.data, dst.size().width, dst.size().height, dst.channels(), dst.step1()); //Get OCR result char *outText = api -> GetUTF8Text(); string text = outText; // api -> End(); delete [] outText; //pixDestroy(&image); return text; }
void homogeneousToEuclidean(const Mat & _X, Mat & _x) { int d = _X.rows - 1; const Mat_<T> & X_rows = _X.rowRange(0,d); const Mat_<T> h = _X.row(d); const T * h_ptr = h[0], *h_ptr_end = h_ptr + h.cols; const T * X_ptr = X_rows[0]; T * x_ptr = _x.ptr<T>(0); for (; h_ptr != h_ptr_end; ++h_ptr, ++X_ptr, ++x_ptr) { const T * X_col_ptr = X_ptr; T * x_col_ptr = x_ptr, *x_col_ptr_end = x_col_ptr + d * _x.step1(); for (; x_col_ptr != x_col_ptr_end; X_col_ptr+=X_rows.step1(), x_col_ptr+=_x.step1() ) *x_col_ptr = (*X_col_ptr) / (*h_ptr); } }
blok::blok(Mat input_block, int _size){ //content = vector<unsigned int>(size,0); unsigned char *input = (unsigned char*)(input_block.data); for(int i=0;i<size;i++) for(int j=0;j<size;j++) content.push_back(input[input_block.step1()*i+j]); weight=1; size=_size; licznik =0; }
void ImageWindow::showImage(Mat im) { Mat rgb; if (im.channels()==3) cvtColor(im, rgb, CV_BGR2RGB); else cvtColor(im, rgb, CV_GRAY2RGB); QImage imQ((const uchar*)rgb.data, rgb.cols, rgb.rows, rgb.step1(), QImage::Format_RGB888); this->setPixmap(QPixmap::fromImage(imQ)); }
static void CentroidOrientationICAngles(const Mat& img, const std::vector<cv::Point2d>& pts, const std::vector<int> & u_max, int half_k, std::vector<float> & angles) { assert(img.channels() == 1); assert(img.type() == CV_8UC1); int step = (int)img.step1(); angles.resize(pts.size()); for(size_t ptidx = 0; ptidx < pts.size(); ptidx++ ) { // const Rect& layer = layerinfo[pts[ptidx].octave]; // const uchar* center = &img.at<uchar>(cvRound(pts[ptidx].pt.y) + layer.y, cvRound(pts[ptidx].pt.x) + layer.x); int y = cvRound(pts[ptidx].y); int x = cvRound(pts[ptidx].x); if (x <= half_k || x + half_k >= img.cols || y <= half_k || y + half_k >= img.rows) { angles[ptidx] = 0.0f; // out of boundary samples continue; } const uchar* center = &img.at<uchar>(y, x); int m_01 = 0, m_10 = 0; // Treat the center line differently, v=0 for (int u = -half_k; u <= half_k; ++u){ m_10 += u * center[u]; } // Go line by line in the circular patch for (int v = 1; v <= half_k; ++v) { // Proceed over the two lines int v_sum = 0; int d = u_max[v]; for (int u = -d; u <= d; ++u) { int val_plus = center[u + v*step], val_minus = center[u - v*step]; v_sum += (val_plus - val_minus); m_10 += u * (val_plus + val_minus); } m_01 += v * v_sum; } angles[ptidx] = cv::fastAtan2((float)m_01, (float)m_10); } }
void fconv_SSE( const Mat &A, const Mat &F, Mat &R ) { int RowA = A.rows, ColA = A.cols, NumFeatures = A.channels(); int RowF = F.rows, ColF = F.cols, ChnF = F.channels(); if( NumFeatures!=ChnF || (NumFeatures%4) ) throw runtime_error(""); int loop = NumFeatures / 4; int RowR = RowA - RowF + 1, ColR = ColA - ColF + 1; float *R_src0 = (float*)R.data; int Rstep = R.step1(); const float *F_src = F.ptr<float>(0,0); const float *A_src0 = A.ptr<float>(0,0); __m128 a,b,c; for( int rr=0; rr<RowR; rr++ ){ const float *A_src1 = A_src0 + rr*A.cols*NumFeatures; // start addr of A.row(rr) float *R_scr1 = R_src0 + rr*Rstep; // start addr of R.row(rr) for( int cc=0; cc<ColR; cc++ ){ const float *A_src= A_src1 + cc*NumFeatures;// A.ptr<float>(rr,cc); float *R_src = R_scr1 + cc; // An acceleration trick of using SSE programming >>> __m128 v = _mm_setzero_ps(); const float *B_off = F_src; for( int rp=0; rp<RowF; rp++ ){ const float *A_off = A_src + rp*A.cols*NumFeatures; for( int cp=0; cp<ColF; cp++ ){ for( int l=0; l<loop; l++ ){ a = _mm_load_ps(A_off); b = _mm_load_ps(B_off); c = _mm_mul_ps(a, b); v = _mm_add_ps(v, c); A_off += 4; B_off += 4; } } } #ifdef WIN32 *R_src = v.m128_f32[0] + v.m128_f32[1] + v.m128_f32[2] + v.m128_f32[3]; #else float buf[4] __attribute__ ((aligned (16))); _mm_store_ps(buf, v); _mm_empty(); *R_src = buf[0]+buf[1]+buf[2]+buf[3]; #endif } } }
string OCR::getText(Mat src) { if (!src.data) { cerr << "getText: No image data!" << endl; return string(""); } // tesseract::TessBaseAPI *api = new tesseract::TessBaseAPI(); // char *configs[] = {"myconfig"}; // int configs_size = 1; // if (!api -> SetVariable("use_definite_ambigs_for_classifier", "1")) // { // cerr << "Unable to set use_definite_ambigs_for_adaption" <<endl; // exit(-1); // } // if (!api -> SetVariable("use_ambigs_for_adaption", "1")) // { // cerr << "Unable to set use_ambigs_for_adaption" <<endl; // exit(-1); // } // if (api -> Init(NULL, "eng2+fra2+deu2+ita2", tesseract::OEM_DEFAULT, configs, configs_size, NULL, NULL, false)) // { // fprintf(stderr, "Could not initialize tesseract.\n"); // exit(-1); // } Mat dst; preprocess(src, dst); api -> SetImage((uchar*)dst.data, dst.size().width, dst.size().height, dst.channels(), dst.step1()); //Get OCR result char *outText = api -> GetUTF8Text(); string text = outText; // api -> End(); delete [] outText; //pixDestroy(&image); return text; }
string LabelOCR::runPrediction2(const Mat &labelImage, int i){ string t1; if (labelImage.empty()) return (t1); Mat textImage; Mat drawImage = labelImage.clone(); double labelROI_x = labelImage.cols*0.15; // initial point x double labelROI_y = labelImage.rows*0.20; // initial point y double labelROI_w = labelImage.cols*0.5; // width double labelROI_h = labelImage.rows*0.15; // heigth Rect labelROI(labelROI_x, labelROI_y, labelROI_w, labelROI_h); Mat midImage; preProcess(drawImage, textImage); tess.TesseractRect( textImage.data, 1, textImage.step1(), labelROI.x, labelROI.y, labelROI.width, labelROI.height); // Get the text char* text1 = tess.GetUTF8Text(); t1 = string(text1); if (t1.size() > 2) t1.resize(t1.size() - 2); cout << "label_" << i << ": " << t1 << endl; if (showImages){ putText(drawImage, t1, Point(labelROI.x+7, labelROI.y-5), FONT_HERSHEY_PLAIN, 1.5, Scalar(0, 0, 255), 2, 8); // CV_FONT_HERSHEY_SIMPLEX rectangle(drawImage, labelROI, Scalar(0, 0, 255), 2, 8, 0); // stringstream ss; ss << i; string str = ss.str(); //imshow("label_"+str, labelImage); imshow("textImage_2_"+str, textImage); imshow("letters_2_"+str, drawImage); } return (t1); }
void fconv_1( const Mat &A, const Mat &F, Mat &R ) { int RowA = A.rows, ColA = A.cols, NumFeatures = A.channels(); int RowF = F.rows, ColF = F.cols, ChnF = F.channels(); if( NumFeatures!=ChnF ) throw runtime_error(""); int RowR = RowA - RowF + 1, ColR = ColA - ColF + 1; float *Rpt = (float*)R.data; int Rstep = R.step1(); for( int r=0; r!=RowR; r++ ){ float *pt = Rpt + r*Rstep; for( int c=0; c!=ColR; c++ ){ Mat Asub = A( Rect(c,r,ColF,RowF) ); *(pt++) = (float)( F.dot( Asub ) ); } } }
string LabelOCR::runPrediction1(const Mat &labelImage, int i){ string t1; if (labelImage.empty()) return (t1); Mat textImage; Mat drawImage = labelImage.clone(); Mat midImage; preProcess(drawImage, textImage); double left_slice = 0.17; double labelROI_x = textImage.size().width * left_slice; // initial point x double labelROI_y = 0; //textImage.rows*0.76; // initial point y double labelROI_w = textImage.size().width * (1 - left_slice); // width double labelROI_h = textImage.size().height; // heigth Rect labelROI(labelROI_x, labelROI_y, labelROI_w, labelROI_h); tess.TesseractRect( textImage.data, 1, textImage.step1(), labelROI.x, labelROI.y, labelROI.width, labelROI.height); // Get the text char* text1 = tess.GetUTF8Text(); t1 = string(text1); if (t1.size() > 2) t1.resize(t1.size() - 2); if (showImages){ ImageProcess tem; IplImage* temI = new IplImage(textImage); IplImage* temI2 = NULL; CvRect* labelROI2 = new CvRect; labelROI2->x = labelROI_x; labelROI2->y = labelROI_y; labelROI2->width = labelROI_w; labelROI2->height = labelROI_h; tem.CutImage(temI, labelROI2, temI2); tem.ShowImage(temI2); } return (t1); }
int main() { Mat findImage = imread("sudo.jpg", IMREAD_GRAYSCALE); //이 이미지 int tempsudo[81] = { 0 }; int sudoku[9][9] = { 0 }; Mat cloneImage = findImage.clone(); threshold(findImage, findImage, 200, 255, THRESH_BINARY); //adaptiveThreshold(findImage, findImage, 255, ADAPTIVE_THRESH_MEAN_C, THRESH_BINARY, 21, 2); imshow("findImage", findImage); waitKey(); Mat srcImage2 = findImage.clone(); Mat dstImage(srcImage2.size(), CV_8UC3); vector<vector<Point> > beforeContoursforRectangle;//스도쿠 이미지만 빼기위한 경계선 vector<vector<Point> > AfterContoursforSmallRectangle; //스도쿠에서 작은 네모만 빼기위한경계선 vector<vector<Point> > configurBackground; vector<Vec4i> hierarchy; //외곽선용 vector<Vec4i> hierarchy2; //81개칸용 vector<Vec4i> hierarchy3; //배경 검사용 vector<vector<Point>> cutSize;//외곽선용 vector<vector<Point>> cutSize2;//81개칸용 vector<vector<Point>> cutSize3; //배경 검사용 int mode = RETR_TREE; int method = CHAIN_APPROX_NONE; Rect r; findContours(findImage, beforeContoursforRectangle, hierarchy, mode, method); //윤곽석 검출 cout << "beforeContoursforRectangle.size()=" << beforeContoursforRectangle.size() << endl; //윤곽선네모 개수 cout << findImage.size() << endl; //이미지 크기 int countMax = beforeContoursforRectangle[0].size(); //최대크기를 찾기위한 변수선언 for (int k = 0; k < beforeContoursforRectangle.size(); k++) { if (beforeContoursforRectangle[k].size()>countMax) countMax = beforeContoursforRectangle[k].size(); } for (int k = 0; k < beforeContoursforRectangle.size(); k++) { if (beforeContoursforRectangle[k].size()>(countMax*0.6))//스토쿠 판만 빼오기 { cutSize.push_back(beforeContoursforRectangle[k]); } } /* //테스트용 Mat testtImage; for (int k = 0; k < cutSize.size(); k++) { // cvtColor(findImage, testtImage, COLOR_GRAY2BGR); r = boundingRect(cutSize[k]);//영역 사각형으로 감쌈 Rect ROI2(r.x, r.y, r.width, r.height); drawContours(testtImage, cutSize, k, Scalar(255, 0, 0), 4); //경계선 그림 cout << r.size() << endl; rectangle(testtImage, ROI2, Scalar(128, 255, 255), 2);//네모로 크림 circle(testtImage, cutSize[k][0], 5, Scalar(123, 123, 123), -1); imshow("testtImage", testtImage); waitKey(); } */ vector<vector<Point>> cuttingArea; int pushArea = -1; int smaller = cutSize[0].size(); for (int k = 1; k < cutSize.size(); k++) { if (cutSize[k].size() < smaller) { smaller = cutSize[k].size(); //제일 작은거 가져옴 sort(cutsize.begin(),cutsize.end())가안되서 이방법 씀 pushArea = k; } } cuttingArea.push_back(cutSize[pushArea]); r = boundingRect(cuttingArea[0]); Rect ROI(r.x, r.y, r.width, r.height); //자를곳을 골라서 영역 표시 cout << "bigSize.size()=" << cutSize.size() << endl; int eraseSpot = -1; int again = 0; int mode2 = RETR_LIST; int mode3 = RETR_LIST; int method2 = CHAIN_APPROX_NONE; int method3 = CHAIN_APPROX_NONE; Mat roi = cloneImage(ROI); //해당 영역만 가지고옴 Mat newImage = repeat(roi, 1, 1); Mat contourImage = newImage.clone(); //배경에 음영있는것들 검출 for (int a = 0; a < contourImage.rows; a++) { for (int b = 0; b < contourImage.cols; b++) { float te = contourImage.at<uchar>(a, b); if (te >= 160 && te < 190) contourImage.at<uchar>(a, b) = 250; } } threshold(contourImage, contourImage, 230, 255, THRESH_BINARY); imshow("contourImage", contourImage); waitKey(); vector<int> configureRectSizeStorage; //빈칸과 숫자칸 저장 vector<int> configureRect; //빈칸숫자칸의 최대 최소값을 알기위해 만듬 vector<Rect> countRect; findContours(contourImage, configurBackground, hierarchy3, mode3, method3); for (int k = 0; k < configurBackground.size(); k++) { cutSize3.push_back(configurBackground[k]); //그 경계선위치들을 넣음 } Mat configureBackgroundImage(contourImage.size(), CV_8UC1); for (int k = 0; k < cutSize3.size(); k++) { // cvtColor(contourImage, configureBackgroundImage, COLOR_GRAY2BGR); r = boundingRect(cutSize3[k]);//영역 사각형으로 감쌈 Rect ROI2(r.x, r.y, r.width, r.height); drawContours(configureBackgroundImage, cutSize3, k, Scalar(255, 0, 0), 4); //경계선 그림 //cout << r.size() << endl; rectangle(configureBackgroundImage, ROI2, Scalar(128, 255, 255), 2);//네모로 크림 if ((r.width*r.height)>(configureBackgroundImage.rows*configureBackgroundImage.cols) - 20000) { //최대영역은 받지 않음 //imshow("resultImage", resultImage); //waitKey(); goto here234; } configureRectSizeStorage.push_back(r.width*r.height); //sorting하기 위해 정리 here234:{} circle(configureBackgroundImage, cutSize3[k][0], 5, Scalar(123, 123, 123), -1); //imshow("resultImage", configureBackgroundImage); //waitKey(); } sort(configureRectSizeStorage.begin(), configureRectSizeStorage.end()); int tSpot = -1; int tagain = 0; for (int k = 0; k < configureRectSizeStorage.size(); k++) { if (k == configureRectSizeStorage.size() - 1) break; if ((configureRectSizeStorage[k + 1] - configureRectSizeStorage[k]) >500) { tSpot = k; //500이 차이나면 따로 넣을곳 정리 break; } } for (int k = tSpot + 1; k < configureRectSizeStorage.size(); k++) { if (tSpot == -1) configureRect.push_back(configureRectSizeStorage[tagain++]); //그냥 집어 넣음 else configureRect.push_back(configureRectSizeStorage[k]); //81개 네모 영역만 집어넣음 } int minRectSize2 = configureRect.front(); //최소 네모 사이즈 int maxRectSize2 = configureRect[configureRect.size() - 1]; //최대 네모 사이즈 Mat lastConfigure; for (int k = 0; k < cutSize3.size(); k++) { cvtColor(contourImage, lastConfigure, COLOR_GRAY2BGR); //imshow("testImage", testImage); r = boundingRect(cutSize3[k]); Rect ROI2(r.x, r.y, r.width, r.height); //cout << r.size() << endl; rectangle(lastConfigure, ROI2, Scalar(128, 255, 255), 2);//그림 if ((minRectSize2 <= (r.width*r.height)) && ((r.width*r.height) <= maxRectSize2)) countRect.push_back(ROI2); //해당 영역만 비교 하기 위해 넣어줌 //imshow("lastConfigure", lastConfigure); //waitKey(); } vector<int>params; //압축양식사용 params.push_back(IMWRITE_JPEG_QUALITY); params.push_back(9); imwrite("sudoOnly.jpg", newImage, params); Mat sudokuImage = imread("sudoOnly.jpg", IMREAD_GRAYSCALE); Mat realImage = imread("sudoOnly.jpg", IMREAD_GRAYSCALE); Mat testSudo = sudokuImage.clone(); //나중에 확인할거 Size size(5, 5); Mat rectKernel = getStructuringElement(MORPH_RECT, size); Mat elipseKernel = getStructuringElement(MORPH_ELLIPSE, size); Mat crossKernel = getStructuringElement(MORPH_CROSS, size); if (countRect.size() != 81) { cout << "안되지롱" << endl; waitKey(); goto jumpThreshold; } threshold(sudokuImage, sudokuImage, 230, 255, THRESH_BINARY); //영상 이진화 imshow("teswtsteswtse", sudokuImage); waitKey(); goto jumpAdaptiveThreshold; //morphologyEx(sudokuImage, sudokuImage, MORPH_CLOSE, rectKernel, Point(-1, -1), 1); jumpThreshold: //threshold(sudokuImage, sudokuImage, 200, 255, THRESH_BINARY); //threshold(sudokuImage, sudokuImage, 200, 255, THRESH_OTSU+THRESH_BINARY); //영상 이진화 adaptiveThreshold(sudokuImage, sudokuImage, 255, ADAPTIVE_THRESH_GAUSSIAN_C, THRESH_BINARY, 21, 1); //morphologyEx(sudokuImage, sudokuImage, MORPH_GRADIENT, crossKernel, Point(-1, -1), 1); erode(sudokuImage, sudokuImage, crossKernel, Point(-1, -1), 1); dilate(sudokuImage, sudokuImage, elipseKernel, Point(-1, -1), 1); jumpAdaptiveThreshold: imshow("sudokuImage", sudokuImage); waitKey(); Mat testImage = realImage.clone();//스도쿠 된것만 복사시킴 Mat resultImage(testImage.size(), CV_8UC3); Mat testSudoImage(realImage.size(), CV_8UC3); vector<int> rectSizeStorage; //빈칸과 숫자칸 저장 vector<int> realRect; //빈칸숫자칸의 최대 최소값을 알기위해 만듬 vector<Rect> sudokuRect; //칸마다 잘라진 영역 저장된곳 vector<Rect> temp; threshold(testImage, testImage, 200, 255, THRESH_OTSU + THRESH_BINARY); //waitKey(); findContours(sudokuImage, AfterContoursforSmallRectangle, hierarchy2, mode2, method2); //스도쿠 원형만 자른곳에서 다시 경계선 그림 for (int k = 0; k < AfterContoursforSmallRectangle.size(); k++) { cutSize2.push_back(AfterContoursforSmallRectangle[k]); //그 경계선위치들을 넣음 } for (int k = 0; k < cutSize2.size(); k++) { // cvtColor(testImage, resultImage, COLOR_GRAY2BGR); r = boundingRect(cutSize2[k]);//영역 사각형으로 감쌈 Rect ROI2(r.x, r.y, r.width, r.height); drawContours(resultImage, cutSize2, k, Scalar(255, 0, 0), 4); //경계선 그림 //cout << r.size() << endl; rectangle(resultImage, ROI2, Scalar(128, 255, 255), 2);//네모로 크림 if ((r.width*r.height)>(resultImage.rows*resultImage.cols) - 20000) { //최대영역은 받지 않음 //imshow("resultImage", resultImage); //waitKey(); goto here; } rectSizeStorage.push_back(r.width*r.height); //sorting하기 위해 정리 here:{} circle(resultImage, cutSize2[k][0], 5, Scalar(123, 123, 123), -1); //imshow("resultImage", resultImage); //waitKey(); } sort(rectSizeStorage.begin(), rectSizeStorage.end()); eraseSpot = -1; again = 0; for (int k = 0; k < rectSizeStorage.size(); k++) { if (k == rectSizeStorage.size() - 1) break; if ((rectSizeStorage[k + 1] - rectSizeStorage[k]) >500) { eraseSpot = k; //500이 차이나면 따로 넣을곳 정리 } } for (int k = eraseSpot + 1; k < rectSizeStorage.size(); k++) { if (eraseSpot == -1) realRect.push_back(rectSizeStorage[again++]); //그냥 집어 넣음 else realRect.push_back(rectSizeStorage[k]); //81개 네모 영역만 집어넣음 } //소팅이 이미 되서 들어가므로 할 필요 없음 int minRectSize = realRect.front(); //최소 네모 사이즈 int maxRectSize = realRect[realRect.size() - 1]; //최대 네모 사이즈 for (int k = 0; k < cutSize2.size(); k++) { cvtColor(testImage, resultImage, COLOR_GRAY2BGR); //imshow("testImage", testImage); r = boundingRect(cutSize2[k]); Rect ROI2(r.x, r.y, r.width, r.height); //cout << r.size() << endl; rectangle(resultImage, ROI2, Scalar(128, 255, 255), 2);//그림 if ((minRectSize <= (r.width*r.height)) && ((r.width*r.height) <= maxRectSize)) temp.push_back(ROI2); //해당 영역만 비교 하기 위해 넣어줌 // imshow("resultImage2", resultImage); //waitKey(); } for (int k = temp.size() - 1; k >= 0; k--) sudokuRect.push_back(temp[k]); //반대로 시작하므로 처음1칸부터 비교하기위해 역으로 넣음 temp.clear(); vector<int> testSortingOk; //각 줄이 순서대로 소팅이 안되있으므로 각 줄마다 왼쪽부터 오른쪽으로 되게 바꿈 for (int i = 0; i < 81; i += 9) { int ty = sudokuRect[i].y; int ti = i; testSortingOk.clear(); for (int j = i; j < ti + 9; j++) { testSortingOk.push_back(sudokuRect[j].x); } sort(testSortingOk.begin(), testSortingOk.end()); int k = 0; for (int j = i; j < ti + 9; j++) { if (testSortingOk[k] == sudokuRect[j].x) temp.push_back(sudokuRect[j]); else { for (int t = i; t <= ti + 9; t++) { if (testSortingOk[k] == sudokuRect[t].x) { temp.push_back(sudokuRect[t]); break; } } } k++; } } sudokuRect.clear(); erode(resultImage, resultImage, crossKernel, Point(-1, -1), 1); dilate(resultImage, resultImage, elipseKernel, Point(-1, -1), 1); for (int k = 0; k < temp.size(); k++) sudokuRect.push_back(temp[k]); for (int k = 0; k < sudokuRect.size(); k++) { rectangle(resultImage, sudokuRect[k], Scalar(128, 255, 255), 2);//그림 imshow("testSudoImage34", resultImage); waitKey(); } const char *path = "/tessdate"; TessBaseAPI tess; //tesseract 선언 //TessBaseAPI *api = new TessBaseAPI(); tess.Init(NULL, "eng", tesseract::OEM_DEFAULT); //한국어로 인식 기본 숫자 되어있음 /* if (api->Init(NULL, "eng")) { fprintf(stderr, "could not initailze teseract\n"); exit(1); } */ string tessRecogNum[81][1]; //글자로 인식해오므로 넣을곳 만들어줌 int sudoTestte[81]; //스도쿠 번호 넣을곳을 만들어줌 int d = 0; for (int i = 0; i<sudokuRect.size(); i++) { cvtColor(testSudo, testSudoImage, COLOR_GRAY2BGR); rectangle(testSudoImage, sudokuRect[i], Scalar(128, 255, 255), 2);//그림 Mat cutImage = testSudo(sudokuRect[i]); // imshow("cutImage", cutImage); Mat tempImage = repeat(cutImage, 1, 1); Mat numberImage = tempImage.clone();//스도쿠 된것만 복사시킴 //imshow("numberImage", numberImage); imwrite("numberImage.jpg", numberImage, params); Mat resultNImage(tempImage.size(), CV_8UC3); waitKey(); int height = tempImage.size().height; int width = tempImage.size().width; int continueNum = 0; //0이 계속되는 수 선언 int testPixel = (height*width); //최대 픽셀 받아옴 //그 칸이 빈칸일 경우 골라서 0을 넣음 /* for (int a = 0; a < tempImage.rows; a++) { for (int b = 0; b < tempImage.cols; b++) { float te = tempImage.at<uchar>(a, b); if (continueNum >= testPixel) break; if (te >= 190 && te <= 200) tempImage.at<uchar>(a, b) = 255; if (te > 200) continueNum++; } if (continueNum >= (testPixel - 10)) break; } */ if (continueNum >= testPixel){ sudoTestte[d++] = atoi("0"); tessRecogNum[i][0] = '0'; continue; } //imshow("tempImage", tempImage); //waitKey(); tess.SetImage((uchar*)tempImage.data, tempImage.size().width, tempImage.size().height, tempImage.channels(), tempImage.step1()); //이미지의 데이터 넓이 높이와 채널을 받아옴 //Pix *image = pixRead("numberImage.jpg"); //api->SetImage(image); // tess.Recognize(0); //인식 시킴 const char * out = tess.GetUTF8Text(); //그걸 utf8text로 인식시킴 //const char * out = api.GetUTF8Text(); tessRecogNum[i][0] = out; if (atoi(out) > 9 || atoi(out) < 0) sudoTestte[d++] = 0; else sudoTestte[d++] = atoi(out); //printf("%s", out); //cout << endl; imshow("testSudoImage", testSudoImage); //waitKey(); } cout << endl; for (int i = 0; i < 81; i++) { if (i % 9 == 0 && i>1) cout << endl; cout << sudoTestte[i] << " "; } waitKey(); return 0; }
void HOGFeatures<T>::features(const Mat& imm, Mat& featm) const { // compute the size of the output matrix assert(imm.channels() == 1 || imm.channels() == 3); bool color = (imm.channels() == 3); const Size imsize = imm.size(); const Size blocks = Size(round((float)imsize.width / (float)binsize_), round((float)imsize.height / (float)binsize_)); const Size outsize = Size(max(blocks.width-2, 0), max(blocks.height-2, 0)); const Size visible = blocks*binsize_; Mat histm = Mat::zeros(Size(blocks.width*norient_, blocks.height), DataType<T>::type); Mat normm = Mat::zeros(Size(blocks.width, blocks.height), DataType<T>::type); featm = Mat::zeros(Size(outsize.width*flen_, outsize.height), DataType<T>::type); // get the stride of each of the matrices const int imstride = imm.step1(); const int histstride = histm.step1(); const int normstride = normm.step1(); const int featstride = featm.step1(); // epsilon to avoid division by zero const double eps = 0.0001; // unit vectors to compute gradient orientation const T uu[9] = {1.000, 0.9397, 0.7660, 0.5000, 0.1736, -0.1736, -0.5000, -0.7660, -0.9397}; const T vv[9] = {0.000, 0.3420, 0.6428, 0.8660, 0.9848, 0.9848, 0.8660, 0.6428, 0.3420}; // calculate the zero offset const IT* im = imm.ptr<IT>(0); T* const hist = histm.ptr<T>(0); T* const norm = normm.ptr<T>(0); T* const feat = featm.ptr<T>(0); // TODO: source image may not be continuous! for (int y = 1; y < visible.height-1; ++y) { for (int x = 1; x < visible.width-1; ++x) { T dx, dy, v; // grayscale image if (!color) { const IT* s = im + min(x, imm.cols-2) + min(y, imm.rows-2)*imstride; dy = *(s+imstride) - *(s-imstride); dx = *(s+1) - *(s-1); v = dx*dx + dy*dy; } // color image // OpenCV uses an interleaved format: BGR-BGR-BGR // Matlab uses a planar format: RRR-GGG-BBB if (color) { const IT* s = im + 3 * min(x, imm.cols-2) + min(y, imm.rows-2)*imstride; // blue image channel T dyb = *(s+imstride) - *(s-imstride); T dxb = *(s+3) - *(s-3); T vb = dxb*dxb + dyb*dyb; // green image channel s += 1; T dyg = *(s+imstride) - *(s-imstride); T dxg = *(s+3) - *(s-3); T vg = dxg*dxg + dyg*dyg; // third image channel s += 1; dy = *(s+imstride) - *(s-imstride); dx = *(s+3) - *(s-3); v = dx*dx + dy*dy; // pick the channel with the strongest gradient if (vg > v) { v = vg; dx = dxg; dy = dyg; } if (vb > v) { v = vb; dx = dxb; dy = dyb; } } // snap to one of 18 orientations T best_dot = 0; int best_o = 0; for (int o = 0; o < norient_/2; ++o) { T dot = uu[o]*dx + vv[o]*dy; if (dot > best_dot) { best_dot = dot; best_o = o; } else if (-dot > best_dot) { best_dot = -dot; best_o = o+norient_/2; } } // add to 4 histograms around pixel using linear interpolation T yp = ((T)y+0.5)/(T)binsize_ - 0.5; T xp = ((T)x+0.5)/(T)binsize_ - 0.5; int iyp = (int)floor(yp); int ixp = (int)floor(xp); T vy0 = yp-iyp; T vx0 = xp-ixp; T vy1 = 1.0-vy0; T vx1 = 1.0-vx0; v = sqrt(v); if (iyp >= 0 && ixp >= 0) *(hist + iyp*histstride + ixp*norient_ + best_o) += vy1*vx1*v; if (iyp >= 0 && ixp+1 < blocks.width) *(hist + iyp*histstride + (ixp+1)*norient_ + best_o) += vx0*vy1*v; if (iyp+1 < blocks.height && ixp >= 0) *(hist + (iyp+1)*histstride + ixp*norient_ + best_o) += vy0*vx1*v; if (iyp+1 < blocks.height && ixp+1 < blocks.width) *(hist + (iyp+1)*histstride + (ixp+1)*norient_ + best_o) += vy0*vx0*v; } } // compute the energy in each block by summing over orientations for (int y = 0; y < blocks.height; ++y) { const T* src = hist + y*histstride; T* dst = norm + y*normstride; T const * const dst_end = dst + blocks.width; while (dst < dst_end) { *dst = 0; for (int o = 0; o < norient_/2; ++o) { *dst += square( *src + *(src+norient_/2) ); src++; } dst++; src += norient_/2; } } // compute the features for (int y = 0; y < outsize.height; ++y) { for (int x = 0; x < outsize.width; ++x) { T* dst = feat + y*featstride + x*flen_; T* p, n1, n2, n3, n4; const T* src; p = norm + (y+1)*normstride + (x+1); n1 = 1.0f / sqrt(*p + *(p+1) + *(p+normstride) + *(p+normstride+1) + eps); p = norm + y*normstride + (x+1); n2 = 1.0f / sqrt(*p + *(p+1) + *(p+normstride) + *(p+normstride+1) + eps); p = norm + (y+1)*normstride + x; n3 = 1.0f / sqrt(*p + *(p+1) + *(p+normstride) + *(p+normstride+1) + eps); p = norm + y*normstride + x; n4 = 1.0f / sqrt(*p + *(p+1) + *(p+normstride) + *(p+normstride+1) + eps); T t1 = 0, t2 = 0, t3 = 0, t4 = 0; // contrast-sensitive features src = hist + (y+1)*histstride + (x+1)*norient_; for (int o = 0; o < norient_; ++o) { T val = *src; T h1 = min(val * n1, (T)0.2); T h2 = min(val * n2, (T)0.2); T h3 = min(val * n3, (T)0.2); T h4 = min(val * n4, (T)0.2); *(dst++) = 0.5 * (h1 + h2 + h3 + h4); src++; t1 += h1; t2 += h2; t3 += h3; t4 += h4; } // contrast-insensitive features src = hist + (y+1)*histstride + (x+1)*norient_; for (int o = 0; o < norient_/2; ++o) { T sum = *src + *(src+norient_/2); T h1 = min(sum * n1, (T)0.2); T h2 = min(sum * n2, (T)0.2); T h3 = min(sum * n3, (T)0.2); T h4 = min(sum * n4, (T)0.2); *(dst++) = 0.5 * (h1 + h2 + h3 + h4); src++; } //texture features *(dst++) = 0.2357 * t1; *(dst++) = 0.2357 * t2; *(dst++) = 0.2357 * t3; *(dst++) = 0.2357 * t4; // truncation feature *dst = 0; } } }
void RecognizeLP::read_image(int width, int height, char *image, Mat& scene_plate, string& lpr,int& count_letters) { cv::Mat Image(height, width, CV_8UC3, image); // you may need to define the area of interest, where the test is found cout<<"count_letters: "<<count_letters<<endl; // initializing Tesseract API char *outText; double confidence = 0; //do{ tesseract::TessBaseAPI *tess_api = new tesseract::TessBaseAPI(); if (tess_api->Init(NULL, "eng")) // eng is a flag of which trained language you use, if you just train your own language, you gave "XYZ" as a falge, you have to use it here { cout<<"Could not initialize tesseract.\n"; exit(1); } //tess_api->SetVariable("tessedit_char_whitelist", "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz012345789"); //tess_api->SetVariable("tessedit_char_whitelist", "0123456789"); if(count_letters < 2) tess_api->SetVariable("tessedit_char_whitelist", "ABCDEFGHIJKLMNOPQRSTUVWXYZ"); if(count_letters >=2 && count_letters < 4) tess_api->SetVariable("tessedit_char_whitelist", /*"ABCDEFGHIJKLMNOPQRSTUVWXYZ"*/"0123456789"); if(count_letters>=4 && count_letters < 6) tess_api->SetVariable("tessedit_char_whitelist", "ABCDEFGHIJKLMNOPQRSTUVWXYZ"); if(count_letters>=6 && count_letters < 10) tess_api->SetVariable("tessedit_char_whitelist", /*"ABCDEFGHIJKLMNOPQRSTUVWXYZ"*/"0123456789"); //tess_api->SetVariable("tessedit_char_whitelist", "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"); // if(count_letters>14) // tess_api->SetVariable("tessedit_char_whitelist", /*"ABCDEFGHIJKLMNOPQRSTUVWXYZ"*/"0123456789"); // else // tess_api->SetVariable("tessedit_char_whitelist", "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789X"); tess_api->SetVariable("classify_font_name", "Arial.ttf"); tess_api->SetVariable("segment_penalty_garbage", "0"); tess_api->SetVariable("segment_penalty_dict_nonword", "0"); tess_api->SetVariable("segment_penalty_dict_frequent_word", "0"); tess_api->SetVariable("segment_penalty_dict_case_ok", "0"); tess_api->SetVariable("segment_penalty_dict_case_bad", "0"); if(!tess_api->SetVariable("tessedit_enable_doc_dict", "0")) { cout << "Unable to enable dictionary" << endl; } tess_api->SetPageSegMode(tesseract::PSM_SINGLE_WORD); tess_api->SetImage((uchar*)scene_plate.data, scene_plate.size().width,scene_plate.size().height,scene_plate.channels(),scene_plate.step1()); tess_api->Recognize(0); //char* out =tess_api->GetUTF8Text(); string temp = tess_api->GetUTF8Text(); temp.erase(std::remove(temp.begin(), temp.end(), '\n'), temp.end()); temp.erase(std::remove(temp.begin(), temp.end(), ' '), temp.end()); confidence = tess_api->MeanTextConf(); //cout<<"OCR output:"<< out<< " with confidence "<<confidence<<endl; //lpr << out; //cout<<temp.length()<<endl; // if(temp.length() <= 5){ // lpr +=temp; // if( temp.length() == 1 || temp.length() == 2 || temp.length() == 5 || temp.length() == 6 && isalpha(temp[0])){ // if(temp.length() == 1) lpr.append(temp); count_letters +=temp.length(); // } // else if( temp.length() == 3 || temp.length() == 4 || temp.length() == 7 || temp.length() == 8 || temp.length() == 9 || temp.length() == 10 && isdigit(temp[0])){ // lpr.append(temp); // count_letters +=temp.length(); // } // else{ // cout<<"Not a valid License Plate"<<endl; // exit(0); // } cout<<count_letters - 1<<"\t|\t"<<lpr<<endl; // } // else{ // count_non_letters +=temp.length(); // } //lpr.append(out); //cout<<lpr; //}while(confidence < 90); }
int detectNumber(Mat img){ //Mat circ = copyContour(img, circle); inRange(img, Scalar(0, 0, 51), Scalar(255, 255, 255), img); //filter black tess.SetImage((uchar*)img.data, img.size().width, img.size().height, img.channels(), img.step1()); //tess.SetRectangle(circle[0]-circle[2], circle[1]-circle[2],2*circle[2],2*circle[2]); string out = string (tess.GetUTF8Text()); out.erase( std::remove_if( out.begin(), out.end(), ::isspace ), out.end() ); const char* result = out.c_str(); //printf("%s\n", result); switch(atoi(result)){ case 10: return 5; case 20: return 6; case 30: return 7; case 40: return 8; case 50: return 9; case 60: return 10; case 70: return 11; case 80: return 12; } //rectangle(img, Point(circle[0]-circle[2], circle[1]-circle[2]), Point(circle[0]+circle[2], circle[1]+circle[2]), Scalar (100,255,255),3,8,0); // imwrite("./test.png", img); return -1;}
void run(Mat& image, string& output, vector<Rect>* component_rects=NULL, vector<string>* component_texts=NULL, vector<float>* component_confidences=NULL, int component_level=0) { CV_Assert( (image.type() == CV_8UC1) || (image.type() == CV_8UC3) ); #ifdef HAVE_TESSERACT if (component_texts != 0) component_texts->clear(); if (component_rects != 0) component_rects->clear(); if (component_confidences != 0) component_confidences->clear(); tess.SetImage((uchar*)image.data, image.size().width, image.size().height, image.channels(), image.step1()); tess.Recognize(0); char *outText; outText = tess.GetUTF8Text(); output = string(outText); delete [] outText; if ( (component_rects != NULL) || (component_texts != NULL) || (component_confidences != NULL) ) { tesseract::ResultIterator* ri = tess.GetIterator(); tesseract::PageIteratorLevel level = tesseract::RIL_WORD; if (component_level == OCR_LEVEL_TEXTLINE) level = tesseract::RIL_TEXTLINE; if (ri != 0) { do { const char* word = ri->GetUTF8Text(level); if (word == NULL) continue; float conf = ri->Confidence(level); int x1, y1, x2, y2; ri->BoundingBox(level, &x1, &y1, &x2, &y2); if (component_texts != 0) component_texts->push_back(string(word)); if (component_rects != 0) component_rects->push_back(Rect(x1,y1,x2-x1,y2-y1)); if (component_confidences != 0) component_confidences->push_back(conf); delete[] word; } while (ri->Next(level)); } delete ri; } tess.Clear(); #else cout << "OCRTesseract(" << component_level << image.type() <<"): Tesseract not found." << endl; output.clear(); if(component_rects) component_rects->clear(); if(component_texts) component_texts->clear(); if(component_confidences) component_confidences->clear(); #endif }
int main(int argc, char* argv[]) { // initilize tesseract OCR engine tesseract::TessBaseAPI *myOCR = new tesseract::TessBaseAPI(); printf("Tesseract-ocr version: %s\n", myOCR->Version()); // printf("Leptonica version: %s\n", // getLeptonicaVersion()); if (myOCR->Init(NULL, "eng")) { fprintf(stderr, "Could not initialize tesseract.\n"); exit(1); } tesseract::PageSegMode pagesegmode = static_cast<tesseract::PageSegMode>(7); // treat the image as a single text line myOCR->SetPageSegMode(pagesegmode); // read iamge namedWindow("tesseract-opencv", 0); Mat image = imread("sample.png", 0); // set region of interest (ROI), i.e. regions that contain text Rect text1ROI(80, 50, 800, 110); Rect text2ROI(190, 200, 550, 50); // recognize text myOCR->TesseractRect( image.data, 1, image.step1(), text1ROI.x, text1ROI.y, text1ROI.width, text1ROI.height); const char *text1 = myOCR->GetUTF8Text(); myOCR->TesseractRect( image.data, 1, image.step1(), text2ROI.x, text2ROI.y, text2ROI.width, text2ROI.height); const char *text2 = myOCR->GetUTF8Text(); // remove "newline" string t1(text1); t1.erase(std::remove(t1.begin(), t1.end(), '\n'), t1.end()); string t2(text2); t2.erase(std::remove(t2.begin(), t2.end(), '\n'), t2.end()); // print found text printf("found text1: \n"); printf(t1.c_str()); printf("\n"); printf("found text2: \n"); printf(t2.c_str()); printf("\n"); // draw text on original image Mat scratch = imread("sample.png"); int fontFace = FONT_HERSHEY_PLAIN; double fontScale = 2; int thickness = 2; putText(scratch, t1, Point(text1ROI.x, text1ROI.y), fontFace, fontScale, Scalar(0, 255, 0), thickness, 8); putText(scratch, t2, Point(text2ROI.x, text2ROI.y), fontFace, fontScale, Scalar(0, 255, 0), thickness, 8); rectangle(scratch, text1ROI, Scalar(0, 0, 255), 2, 8, 0); rectangle(scratch, text2ROI, Scalar(0, 0, 255), 2, 8, 0); imshow("tesseract-opencv", scratch); waitKey(0); delete [] text1; delete [] text2; // destroy tesseract OCR engine myOCR->Clear(); myOCR->End(); return 0; }
//---------------------------------------------------------------------------------- void OCRit(Mat inputimg, vector<vector<Point>>points, char data[][60], Mat &outputimg, char lang[]){ TessBaseAPI tess; tess.Init(NULL, lang, OEM_DEFAULT); cout << "\n\n"; for (unsigned int c = 0; c < points.size(); c++){ Mat imag = inputimg(Rect(points[c][0], points[c][1])); Mat img; cvtColor(imag, img, COLOR_BGR2GRAY);//use img to do ocr now tess.SetImage((uchar*)img.data, img.size().width, img.size().height, img.channels(), img.step1()); char* out = tess.GetUTF8Text(); cout << c + 1 << " -- " << out << "\n"; strcpy(data[c],out); //removed to prevent alteration of original pan //rectangle(outputimg, points[c][0], points[c][1],1,4,0); } }
// 因为featpyramid()中对各个pyra.feat[i]进行0/1扩展耗费了大量时间,为了减小这个开支,这里直接对计算的feature扩展 Mat PM_type::features14_2( const Mat &image, const int sbin, const int pad[2] ) { const int dims[3] = { image.rows, image.cols, image.channels() }; const int row_step = image.cols * image.channels(); const float * const imgpt = image.ptr<float>(0,0); if( image.type()!=CV_32FC3 ) throw runtime_error("Invalid input"); // memory for caching orientation histograms & their norms const int blocks[2] = { (int)(0.5f+(float)dims[0]/(float)sbin), (int)(0.5f+(float)dims[1]/(float)sbin) }; const int block_sz = blocks[0] * blocks[1]; const int visible[2] = { blocks[0]*sbin, blocks[1]*sbin }; Mat histmat[9]; float *hist[9]; int hist_step[9]; Mat hist_tmp = Mat::zeros( blocks[0], blocks[1]*9, CV_32FC1 ); for( int i=0; i<9; i++ ){ //histmat[i] = Mat::zeros( blocks[0], blocks[1], CV_32FC1 ); histmat[i] = hist_tmp( Rect(i*blocks[1],0,blocks[1],blocks[0]) ); hist[i] = histmat[i].ptr<float>(0,0); hist_step[i] = histmat[i].step1(); } // 1. Calculate the original HOG for (int yy = 1; yy < visible[0]-1; yy++) { // each row int y = MIN(yy,dims[0]-2); const float *imgpt1 = imgpt + y*row_step; for (int xx = 1; xx < visible[1]-1; xx++) { // each col int x = MIN(xx,dims[1]-2); // b-g-r color at (y,x) is { *s, *(s+1), *(s+2) } const float *s = imgpt1 + x*dims[2]; float Right[3] = { *(s+3), *(s+4), *(s+5) }; float Left[3] = { *(s-3), *(s-2), *(s-1) }; float Up[3] = { *(s-row_step), *(s+1-row_step), *(s+2-row_step) }; float Down[3] = { *(s+row_step), *(s+1+row_step), *(s+2+row_step) }; // gradients and amplitude of orientations of each channel float dxs, dys, vs; float dx, dy, v=-1; for( int i=0; i!=3; i++ ){ dxs = Right[i] - Left[i]; dys = Down[i] - Up[i]; vs = dxs*dxs + dys*dys; if( vs>=v ){ v = vs; dx = dxs; dy = dys; } } //int best_o = yuSnap9_V1( dx, dy ); //int best_o = yuSnap9( dx, dy ); int best_o = 0; { // snap to 1 of the 9 orientations float a[4] = { uu[1]*dx, uu[2]*dx, uu[3]*dx, uu[4]*dx }; float b[4] = { vv[1]*dy, vv[2]*dy, vv[3]*dy, vv[4]*dy }; float dots[9] = { dx, a[0]+b[0], a[1]+b[1], a[2]+b[2], a[3]+b[3], b[3]-a[3], b[2]-a[2], b[1]-a[1], b[0]-a[0] }; // uu[i]*dx+vv[i]*dy float best_dot = 0; for( int i=0; i<9; i++ ){ if( dots[i]<0 ) dots[i] = -dots[i]; if( dots[i]>best_dot ){ best_dot = dots[i]; best_o = i; } } } // add to 4 histograms around pixel using linear interpolation float xp = (xx+0.5f)/(float)sbin - 0.5f; float yp = (yy+0.5f)/(float)sbin - 0.5f; //int ixp = (int)floorf(xp), iyp = (int)floorf(yp); int ixp = (int)xp, iyp = (int)yp; if( xp<0 && xp!=ixp ) ixp--; if( yp<0 && yp!=iyp ) iyp--; int ixp_p = ixp + 1, iyp_p = iyp + 1; float vx0 = xp-ixp, vy0 = yp-iyp; float vx1 = 1.f-vx0, vy1 = 1.f-vy0; v = sqrtf(v); if( ixp<0 ){ ixp = 0; vx1 = 0; } if( ixp_p>=blocks[1] ){ ixp_p = blocks[1] - 1; vx0 = 0; } if( iyp<0 ){ iyp = 0; vy1 = 0; } if( iyp_p>=blocks[0] ){ iyp_p = blocks[0] - 1; vy0 = 0; } float *hist_pt = hist[best_o] + iyp*hist_step[best_o] + ixp; ixp_p = ixp_p - ixp; iyp_p = iyp_p - iyp; *(hist_pt) += vx1*vy1*v; *(hist_pt + ixp_p) += vx0*vy1*v; *(hist_pt + iyp_p*hist_step[best_o]) += vx1*vy0*v; *(hist_pt + iyp_p*hist_step[best_o] + ixp_p) += vx0*vy0*v; } } // 2. Compute energy in each block by summing over orientations Mat normmat = Mat::zeros( blocks[0], blocks[1], CV_32FC1 ); float * const norm = normmat.ptr<float>(0,0); const int norm_step = normmat.step1(); for( int i=0; i<9; i++ ) accumulateSquare( histmat[i], normmat ); // normalization coefficients Mat Normmss(blocks[0]-1,blocks[1]-1,CV_32FC1); float * const Norms = Normmss.ptr<float>(0,0); const int norms_step = Normmss.step1(); for( int i=0; i<Normmss.rows; i++ ){ float *src = norm + i*norm_step; float *dst = Norms + i*norms_step; for( int j=0; j<Normmss.cols; j++ ){ float tmp = *src + *(src+1) + *(src+norm_step) + *(src+norm_step+1) + eps; //*(dst++) = 1.f / sqrtf(tmp); *(dst++) = tmp; src++; } } cv::sqrt( Normmss, Normmss ); Normmss = 1.f / Normmss; // 3. Reduced HOG features. int out[3]; out[0] = MAX(blocks[0]-2, 0); out[1] = MAX(blocks[1]-2, 0); out[2] = 9+4+1; // 14 dimensional features out[2] += 2; // 16 dimensional features finally Mat feat_mat( out[0]+2*pad[0], out[1]+2*pad[1], CV_32FC(out[2]) ); Vec<float,16> init_val; init_val = 0; init_val[13] = 1; feat_mat.setTo( init_val ); float * const feat_data = feat_mat.ptr<float>(pad[0],pad[1]); const int feat_step = feat_mat.step1(); for( int y=0; y<out[0]; y++ ){ float *dst = feat_data + y*feat_step; float *Normpt = Norms + y*norms_step; for( int x=0; x<out[1]; x++ ){ // float n4 = *Normpt; float n2 = *(Normpt+1); float n3 = *(Normpt+norms_step); float n1 = *(Normpt+norms_step+1); Normpt++; float t1 = 0, t2 = 0, t3 = 0, t4 = 0; // 9 contrast-insensitive features for( int i=0; i<9; i++ ){ float src = *( hist[i]+(y+1)*hist_step[i]+x+1 ); //float src = histmat_insens[i].at<float>(y+1,x+1); float h1 = MIN(src * n1, 0.2f); float h2 = MIN(src * n2, 0.2f); float h3 = MIN(src * n3, 0.2f); float h4 = MIN(src * n4, 0.2f); *(dst++) = 0.5f * (h1 + h2 + h3 + h4); t1 += h1; t2 += h2; t3 += h3; t4 += h4; } // 4 texture features *(dst++) = 0.3333f * t1; *(dst++) = 0.3333f * t2; *(dst++) = 0.3333f * t3; *(dst++) = 0.3333f * t4; // 1 truncation feature and 2 supplementary features //dst += 3; *(dst++) = 0; *(dst++) = 0; *(dst++) = 0; } } return feat_mat; }