#include "StdAfx.h" #include "CrossDetector.h" #include #include "schema_struct.h" #define PI 3.1415926535 const int DIRECTION_FLAG[4] = { DIR_FLAG_UP, DIR_FLAG_DOWN, DIR_FLAG_LEFT, DIR_FLAG_RIGHT }; //检测 CCrossDetector::CCrossDetector(int unit_count/*=15*/, double angle/*=0*/, double angle_unit/*=0.5*/, int cross_break/*=4*/, int cross_burr/*=15*/, int grayvalve/*=180*/, int cross_len/*=20*/, int cross_percent/*=80*/) { options.m_CrossArg = unit_count; options.m_CrossBreak = cross_break; options.m_CrossBurr = cross_burr; options.m_CrossGray = grayvalve; options.m_CrossLen = cross_len; options.m_CrossPercent = cross_percent; this->total_angle_count = (unit_count * 2 + 1); arglist_t.resize(total_angle_count); arglist = arglist_t.data(); arglist[0] = static_cast(angle); for (int i = 1; i <= unit_count; i++){ arglist[2 * i - 1] = static_cast(angle + i*angle_unit); arglist[2 * i] = static_cast(angle - i*angle_unit); } buffer_t.resize(2 * 4 * total_angle_count); this->buffer = buffer_t.data(); dx[0] = buffer + total_angle_count * 0; dx[1] = buffer + total_angle_count * 1; dx[2] = buffer + total_angle_count * 2; dx[3] = buffer + total_angle_count * 3; dy[0] = buffer + total_angle_count * 4; dy[1] = buffer + total_angle_count * 5; dy[2] = buffer + total_angle_count * 6; dy[3] = buffer + total_angle_count * 7; for (int i = 0; i < total_angle_count; i++) { dx[0][i] = -sin(arglist[i] * PI / 180.); dy[0][i] = -cos(arglist[i] * PI / 180.); dx[1][i] = sin(arglist[i] * PI / 180.); dy[1][i] = cos(arglist[i] * PI / 180.); dx[2][i] = -cos(arglist[i] * PI / 180.); dy[2][i] = sin(arglist[i] * PI / 180.); dx[3][i] = cos(arglist[i] * PI / 180.); dy[3][i] = -sin(arglist[i] * PI / 180.); } } int CCrossDetector::Detect(const IplImage*img, std::vector&cross) { IplImage t; cvInitImageHeader(&t, cvSize(img->width, img->height), img->depth, img->nChannels, img->origin, img->align); cvSetData(&t, img->imageData, img->widthStep); IplImage * img_ = &t; CvRect rect = cvGetImageROI(img); cvSetImageROI(img_,rect); IplImage * img_binary = cvCreateImage(cvSize(rect.width, rect.height), IPL_DEPTH_8U, 1); IplImage * img_handle = cvCreateImage(cvSize(rect.width, rect.height), IPL_DEPTH_8U, 1); cvZero(img_handle); if (img_->nChannels == 3){ cvCvtColor(img_, img_binary, CV_BGR2GRAY); } else{ cvCopy(img_, img_binary); } //cvSaveImage("D:\\001.png", img_binary); cvAdaptiveThreshold(img_binary, img_binary, 255, CV_ADAPTIVE_THRESH_MEAN_C, CV_THRESH_BINARY, 9, 10); cvSmooth(img_binary, img_binary, CV_BLUR,3,3); cvThreshold(img_binary, img_binary, 255*(18-3)/18, 255, CV_THRESH_BINARY); //cvSaveImage("D:\\002.png", img_binary); //vector signs; for (int y = 0; y < img_binary->height; y++) { for (int x = 0; x < img_binary->width; x++) { if (CV_IMAGE_ELEM(img_handle, unsigned char, y, x)){ continue; } if (CV_IMAGE_ELEM(img_binary, unsigned char, y, x)){ continue; } bool isSign_0 = isSignPossable(img_binary, x, y); if (!isSign_0)continue; SIGN sign; bool isSign_ = isSign(img_binary, x, y, sign); if (isSign_){ int sumx = sign.x; int sumy = sign.y; int sign_count = 1; int sign_ = sign.sign; for (int yy = max(y - 5, 0), endyy = min(img_binary->height, y + 5 + 1); yy < endyy; yy++) { for (int xx = max(x - 5, 0), endxx = min(img_binary->width, x + 5 + 1); xx < endxx; xx++) { if (xx == x&&yy == y)continue; if (CV_IMAGE_ELEM(img_handle, unsigned char, yy, xx))continue; SIGN sign2; bool isSign_2 = isSign(img_binary, xx, yy, sign2); if (isSign_2){ sumx += sign2.x; sumy += sign2.y; sign_ |= sign2.sign; sign_count++; CV_IMAGE_ELEM(img_handle, unsigned char, yy, xx) = 1; } } } CV_IMAGE_ELEM(img_handle, unsigned char, y, x) = 1; sign.x = rect.x + (int)(sumx / (double)sign_count + 0.5); sign.y = rect.y + (int)(sumy / (double)sign_count + 0.5); sign.sign = (SIGND)sign_; //signs.push_back(sign); CvCross cross_; cross_.x = sign.x; cross_.y = sign.y; cross_.sign = sign.sign; cross_.arg = 0; cross.push_back(cross_); } } } cvReleaseImage(&img_binary); cvReleaseImage(&img_handle); return identify::result::IDF_SUCCESS; } CCrossDetector::~CCrossDetector(void) { } bool CCrossDetector::isSign(const IplImage * img_binary, int x, int y, SIGN &sign_) { int width = img_binary->width; int height = img_binary->height; int haveburr; int totalpoints; bool result = false; if (!CV_IMAGE_ELEM(img_binary, unsigned char, y, x)){ for (int arg0 = 0; arg0 < 2 * options.m_CrossArg + 1; arg0++){ int nowburr = 0; int nowsign = 0; for (int dir = 0; dir < 4; dir++){ int breakpoints = 0; int len; for (len = 1; len <= options.m_CrossLen; len++){ int posx = x + (int)(len * dx[dir][arg0] + 0.5); int posy = y + (int)(len * dy[dir][arg0] + 0.5); if (posx < 0 || posx >= width || posy < 0 || posy >= height)break; if (CV_IMAGE_ELEM(img_binary, unsigned char, posy, posx)){ //潜在断点 breakpoints++; if (breakpoints > options.m_CrossBreak){ len -= breakpoints; break; } } else{ breakpoints = 0; } } if (len > options.m_CrossLen){ nowsign |= DIRECTION_FLAG[dir]; } else if (len > options.m_CrossBurr){ nowburr = 1; } } if ((nowsign & 3) && (nowsign & 12)){ //必须有交叉,不能只是直线 if (options.m_CrossPercent != 0){//周围空白检查 int blankpoint = 0; //交叉点周围必须有足够多的空白点 int xx, yy, xx0, yy0; //*********************************右上区域检查********************** totalpoints = options.m_CrossLen / 2; //寻找直线右边界 for (xx = 1; xx <= options.m_CrossLen / 2; xx++){ blankpoint = 0; for (yy = -1; yy >= -options.m_CrossLen / 2; yy--){ int posx = (int)(x + xx * dx[3][arg0] + 0.5); int posy = (int)(y + yy * dy[1][arg0] + 0.5); if (posx < 0 || posx >= width || posy < 0 || posy >= height)break; if (CV_IMAGE_ELEM(img_binary, unsigned char, posy, posx)) blankpoint++; } if (blankpoint > totalpoints * 0.5) break; } if (xx > options.m_CrossLen / 2) continue; xx0 = xx; //寻找直线上边界 for (yy = -1; yy >= -options.m_CrossLen / 2; yy--){ blankpoint = 0; for (xx = 1; xx <= options.m_CrossLen / 2; xx++){ int posx = (int)(x + xx * dx[3][arg0] + 0.5); int posy = (int)(y + yy * dy[1][arg0] + 0.5); if (posx < 0 || posx >= width || posy < 0 || posy >= height)break; if (CV_IMAGE_ELEM(img_binary, unsigned char, posy, posx)) blankpoint++; } if (blankpoint > totalpoints * 0.5) break; } if (yy < -options.m_CrossLen / 2) continue; yy0 = yy; blankpoint = 0; //交叉点周围必须有足够多的空白点 totalpoints = 0; for (yy = 0; yy > -options.m_CrossLen / 2; yy--){ for (xx = 0; xx < options.m_CrossLen / 2 + yy; xx++){ int posx = (int)(x + (xx0 + xx) * dx[3][arg0] + 0.5); int posy = (int)(y + (yy0 + yy) * dy[1][arg0] + 0.5); if (posx < 0 || posx >= width || posy < 0 || posy >= height)break; totalpoints++; if (CV_IMAGE_ELEM(img_binary, unsigned char, posy, posx)) blankpoint++; } } if (blankpoint < totalpoints / 100. * options.m_CrossPercent) continue; //空白点太少 //*********************************左上区域检查********************** totalpoints = options.m_CrossLen / 2; //寻找直线左边界 for (xx = -1; xx >= -options.m_CrossLen / 2; xx--){ blankpoint = 0; for (yy = -1; yy >= -options.m_CrossLen / 2; yy--){ int posx = (int)(x + xx * dx[3][arg0] + 0.5); int posy = (int)(y + yy * dy[1][arg0] + 0.5); if (posx < 0 || posx >= width || posy < 0 || posy >= height)break; if (CV_IMAGE_ELEM(img_binary, unsigned char, posy, posx)) blankpoint++; } if (blankpoint > totalpoints * 0.5) break; } if (xx < -options.m_CrossLen / 2) continue; xx0 = xx; //寻找直线上边界 for (yy = -1; yy >= -options.m_CrossLen / 2; yy--){ blankpoint = 0; for (xx = -1; xx >= -options.m_CrossLen / 2; xx--){ int posx = (int)(x + xx * dx[3][arg0] + 0.5); int posy = (int)(y + yy * dy[1][arg0] + 0.5); if (posx < 0 || posx >= width || posy < 0 || posy >= height)break; if (CV_IMAGE_ELEM(img_binary, unsigned char, posy, posx)) blankpoint++; } if (blankpoint > totalpoints * 0.5) break; } if (yy < -options.m_CrossLen / 2) continue; yy0 = yy; totalpoints = 0; blankpoint = 0; for (yy = 0; yy > -options.m_CrossLen / 2; yy--){ for (xx = 0; xx > -options.m_CrossLen / 2 - yy; xx--){ int posx = (int)(x + (xx0 + xx) * dx[3][arg0] + 0.5); int posy = (int)(y + (yy0 + yy) * dy[1][arg0] + 0.5); if (posx < 0 || posx >= width || posy < 0 || posy >= height)break; totalpoints++; if (CV_IMAGE_ELEM(img_binary, unsigned char, posy, posx)) blankpoint++; } } if (blankpoint < totalpoints / 100. * options.m_CrossPercent) continue; //空白点太少 //*********************************右下区域检查********************** totalpoints = options.m_CrossLen / 2; //寻找直线右边界 for (xx = 1; xx <= options.m_CrossLen / 2; xx++){ blankpoint = 0; for (yy = 1; yy <= options.m_CrossLen / 2; yy++){ int posx = (int)(x + xx * dx[3][arg0] + 0.5); int posy = (int)(y + yy * dy[1][arg0] + 0.5); if (posx < 0 || posx >= width || posy < 0 || posy >= height)break; if (CV_IMAGE_ELEM(img_binary, unsigned char, posy, posx)) blankpoint++; } if (blankpoint > totalpoints * 0.5) break; } if (xx > options.m_CrossLen / 2) continue; xx0 = xx; //寻找直线下边界 for (yy = 1; yy <= options.m_CrossLen / 2; yy++){ blankpoint = 0; for (xx = 1; xx <= options.m_CrossLen / 2; xx++){ int posx = (int)(x + xx * dx[3][arg0] + 0.5); int posy = (int)(y + yy * dy[1][arg0] + 0.5); if (posx < 0 || posx >= width || posy < 0 || posy >= height)break; if (CV_IMAGE_ELEM(img_binary, unsigned char, posy, posx)) blankpoint++; } if (blankpoint > totalpoints * 0.5) break; } if (yy > options.m_CrossLen / 2) continue; yy0 = yy; totalpoints = 0; blankpoint = 0; for (yy = 0; yy < options.m_CrossLen / 2; yy++){ for (xx = 0; xx < options.m_CrossLen / 2 - yy; xx++){ int posx = (int)(x + (xx0 + xx) * dx[3][arg0] + 0.5); int posy = (int)(y + (yy0 + yy) * dy[1][arg0] + 0.5); if (posx < 0 || posx >= width || posy < 0 || posy >= height)break; totalpoints++; if (CV_IMAGE_ELEM(img_binary, unsigned char, posy, posx)) blankpoint++; } } if (blankpoint < totalpoints / 100. * options.m_CrossPercent) continue; //空白点太少 //*********************************左下区域检查********************** totalpoints = options.m_CrossLen / 2; //寻找直线左边界 for (xx = -1; xx >= -options.m_CrossLen / 2; xx--){ blankpoint = 0; for (yy = 1; yy <= options.m_CrossLen / 2; yy++){ int posx = (int)(x + xx * dx[3][arg0] + 0.5); int posy = (int)(y + yy * dy[1][arg0] + 0.5); if (posx < 0 || posx >= width || posy < 0 || posy >= height)break; if (CV_IMAGE_ELEM(img_binary, unsigned char, posy, posx)) blankpoint++; } if (blankpoint > totalpoints * 0.5) break; } if (xx < -options.m_CrossLen / 2) continue; xx0 = xx; //寻找直线下边界 for (yy = 1; yy <= options.m_CrossLen / 2; yy++){ blankpoint = 0; for (xx = -1; xx >= -options.m_CrossLen / 2; xx--){ int posx = (int)(x + xx * dx[3][arg0] + 0.5); int posy = (int)(y + yy * dy[1][arg0] + 0.5); if (posx < 0 || posx >= width || posy < 0 || posy >= height)break; if (CV_IMAGE_ELEM(img_binary, unsigned char, posy, posx)) blankpoint++; } if (blankpoint > totalpoints * 0.5) break; } if (yy > options.m_CrossLen / 2) continue; yy0 = yy; totalpoints = 0; blankpoint = 0; for (yy = 0; yy < options.m_CrossLen / 2; yy++){ for (xx = 0; xx > -options.m_CrossLen / 2 + yy; xx--){ int posx = (int)(x + (xx0 + xx) * dx[3][arg0] + 0.5); int posy = (int)(y + (yy0 + yy) * dy[1][arg0] + 0.5); if (posx < 0 || posx >= width || posy < 0 || posy >= height)break; totalpoints++; if (CV_IMAGE_ELEM(img_binary, unsigned char, posy, posx)) blankpoint++; } } if (blankpoint < totalpoints / 100. * options.m_CrossPercent) continue; //空白点太少 } if (nowburr){ haveburr = 1; break; } totalpoints = 0; sign_.sign = (SIGND)nowsign; sign_.x = x; sign_.y = y; result = true; for (int dir = 0; dir < 4; dir++){ int breakpoints = 0; if ((nowsign & DIRECTION_FLAG[dir]) != 0) { for (int len = 1; len <= 100; len++){ //按最长边计算角度 int posx = x + (int)(len * dx[dir][arg0] + 0.5); int posy = y + (int)(len * dy[dir][arg0] + 0.5); if (posx < 0 || posx >= width || posy < 0 || posy >= height)break; totalpoints++; if (CV_IMAGE_ELEM(img_binary, unsigned char, posy, posx)){ //潜在断点 breakpoints++; if (breakpoints > options.m_CrossBreak) break; } else{ breakpoints = 0; } } totalpoints -= breakpoints; } } } } } return result; } bool CCrossDetector::isSignPossable(const IplImage * img_binary, int x, int y) { int width = img_binary->width; int height = img_binary->height; bool result = false; if (!CV_IMAGE_ELEM(img_binary, unsigned char, y, x)){ int top = 0, bottom = 0, left = 0, right = 0; {//上 int ys = std::max(0, y - options.m_CrossLen); int ye = std::max(0, y - 1); int xs = std::max(0, x - 2); int xe = std::min(width - 1, x + 2); for (int yy = ys; yy <= ye; yy++) { for (int xx = xs; xx <= xe; xx++) { if (!CV_IMAGE_ELEM(img_binary, unsigned char, yy, xx)){ top++; break; } } } } {//下 int ys = std::min(height - 1, y + 1); int ye = std::min(height - 1, y + options.m_CrossLen); int xs = std::max(0, x - 2); int xe = std::min(width - 1, x + 2); for (int yy = ys; yy <= ye; yy++) { for (int xx = xs; xx <= xe; xx++) { if (!CV_IMAGE_ELEM(img_binary, unsigned char, yy, xx)){ bottom++; break; } } } } {//左 int ys = std::max(0, y - 2); int ye = std::min(height - 1, y + 2); int xs = std::max(0, x - options.m_CrossLen); int xe = std::max(0, x - 1); for (int xx = xs; xx <= xe; xx++) { for (int yy = ys; yy <= ye; yy++) { if (!CV_IMAGE_ELEM(img_binary, unsigned char, yy, xx)){ left++; break; } } } } {//右 int ys = std::max(0, y - 2); int ye = std::min(height - 1, y + 2); int xs = std::min(width - 1, x + 1); int xe = std::min(width - 1, x + options.m_CrossLen); for (int xx = xs; xx <= xe; xx++) { for (int yy = ys; yy <= ye; yy++) { if (!CV_IMAGE_ELEM(img_binary, unsigned char, yy, xx)){ right++; break; } } } } int valve = std::max(5,options.m_CrossLen - 4); if ((left > valve || right > valve) && (top > valve || bottom > valve)){ result = true; } } return result; }