123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445 |
- #include "StdAfx.h"
- #include "CrossDetector.h"
- #include <math.h>
- #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<int>(angle);
- for (int i = 1; i <= unit_count; i++){
- arglist[2 * i - 1] = static_cast<int>(angle + i*angle_unit);
- arglist[2 * i] = static_cast<int>(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<CvCross>&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<SIGN> 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;
- }
|