www.pudn.com > Imagepro.rar > ImgProlib.cpp
// ****************************************************************************** // * 图象处理算法库 // * ---------------------------------------------------------------------------- // * C++ File: imgprolib.cpp // * Header File: imgProlib.h // * // * Description: // * The class of "IMAGE2D" has several operations curently: // * // * ReadBMP() -- read the binary BMP 2D image file // * // * GaussSmooth() -- smooth the image with Gaussian smoothing filter高斯平滑 // * FlattenHistogram() -- equalize the hisrogram of the input image直方图均衡 // * // * Edge Detector // * SobelEdgeDetector() -- Edge detection with Sobel operator Sobel边缘检测 // * CannyEdgeDetector() -- The first drivative of Guaussian edge detector Canny边缘检测 // * // * Thresholding // * SimpleThresholding() -- One threshold is given as an input parameter 指定单阈值 // * SimpleDoubleThresholding() -- Up and down thresholds are given as two input parameters 指定双阈值 // * GlobalThresholding() -- Threshold is selected by top P% of the pixels 全局阈值法 // * // * Thinning() -- Thin the edges after thresholding 细化 // * HoughTransform() -- Hough transform with polar form of the line Hough变换 // * LineFitting() -- Line fitting (Peak fitting) 边线拟合 // * // * Image tools // * ClearImage() -- Clear image to be 0 清除Image // * NegativeImage() -- Make the image to be negative image 图像反相 // * FlipImage() -- Flip the image along the X axis 图像翻转 // * CopyImage() -- Copy one image to another image 图像复制 // * BlendImage() -- Combine two images into one image 图像叠合 // ****************************************************************************** #include "stdafx.h" #include#include #include #include #include #include #include "imgprolib.h" //------------------------------------------------------------- // ReadBMP(): reads the binary BMP 2D image file //------------------------------------------------------------- BOOL IMAGE2D::ReadBMP(char *filename) { FILE *fp; if ((fp = fopen(filename, "r")) == NULL) return FALSE; fclose(fp); AUX_RGBImageRec *image; image = auxDIBImageLoad(filename); width = image->sizeX; height = image->sizeY; gray_level = 255; // maximum gray value input_data = new unsigned char[width*height]; output_data = new unsigned char[width*height]; int format = 3; for(int i = 0; i < height; i ++) for(int j = 0; j < width; j ++) { int offset = i * width * format + j * format; input_data[i * width + j] = (image->data[offset] + image->data[offset + 1] + image->data[offset + 2])/3; } delete image; return TRUE; } //--------------------------------------------------------------- // FlattenHistogram(): equalize the hisrogram of the input image //--------------------------------------------------------------- void IMAGE2D::FlattenHistogram(unsigned char * input_data) { GenHistogram(input_data); int *flatten_table = new int[gray_level + 1]; int i, sum_freq = 0; // create the transformation table of flattened histogram for(i = 0; i <= gray_level; i ++) { sum_freq += histogram[i]; double cc = (double)(gray_level * sum_freq) / (double)(width * height); flatten_table[i] = (int)(cc); } //transform the original image to equalized image for(i = 0; i < height; i ++) for(int j = 0; j < width; j ++) output_data[i*width + j] = flatten_table[input_data[i*width + j]]; delete flatten_table; } //---------------------------------------------------------- //GenHistogram(): generate the hisrogram of the input image //---------------------------------------------------------- void IMAGE2D::GenHistogram(unsigned char *inData) { histogram = new unsigned int[gray_level + 1]; for(int i = 0; i <= gray_level; i ++) histogram[i] = 0; // initialized to be 0 for(i = 0; i < height; i ++) for(int j = 0; j < width; j ++) histogram[inData[i * width + j]] ++; } //---------------------------------------------------------------------------------- //GetHistogram(): generate the hisrogram of the input image with size width x height //---------------------------------------------------------------------------------- unsigned int * IMAGE2D::GetHistogram(unsigned int *inData, int in_width, int in_height) { unsigned int * hist = new unsigned int[gray_level + 1]; for(int i = 0; i <= gray_level; i ++) hist[i] = 0; // initialized to be 0 for(i = 0; i < in_height; i ++) for(int j = 0; j < in_width; j ++) { int k = inData[i * in_width + j]; hist[k] ++; } return hist; } //--------------------------------------------------------------------- //GaussSmooth(): smooth the input image with Gaussian smoothing filter //--------------------------------------------------------------------- void IMAGE2D::GaussSmooth(double sigma, int mask_width, unsigned char * input_data, unsigned char * output_data) { // preprocess the mask_width(在此处针对高斯模板,其矩阵为3×3的。) if(mask_width < 0) mask_width = - mask_width; // mask_width must be positive if(!(mask_width % 2))mask_width ++; // mask_width must be odd when even // allocate the 1D mask matrix and computate its value double *mask = new double[mask_width]; Gauss1D(sigma, mask_width, mask); unsigned char * tmp_data = new unsigned char[width*height]; // storing horizontal smoothing int half_mask_width = (mask_width - 1) / 2; int tmp_num = 3 * half_mask_width; //for boundary unsigned char * tmp = new unsigned char[tmp_num]; #define _CalBoundary(output_data) \ { \ double sum_pixel = 0.0; \ for(k = 0; k < mask_width; k ++) \ sum_pixel += mask[k] * tmp[k]; \ _DT(output_data, i, j) =(int)(sum_pixel); \ } //-------------- CONVOLUTION WITH THE HORIZONAL MASK ----------------- // calculate X-direction smoothed values of the main body of the image for(int i = 0; i < height; i ++) for(int j = half_mask_width; j < width - half_mask_width; j ++) { double sum_pixel = 0.0; for(int k = 0; k < mask_width; k ++) sum_pixel += mask[k] * _DT(input_data, i, j + k - half_mask_width); _DT(tmp_data, i, j) =(int)(sum_pixel); } // calculate the x-direction boundary smoothed pixels of the image for(i = 0; i < height; i ++) { // boundary ( 0 -> half_mask_width ) //----- calculate the tempotary array for(int k = 0; k < half_mask_width; k ++) tmp[k] = _DT(input_data, i, width - half_mask_width + k); for(k = half_mask_width; k < tmp_num; k ++) tmp[k] = _DT(input_data, i, k - half_mask_width); //----- claculate the pixel on the left boundary for(int j = 0; j < half_mask_width; j ++) _CalBoundary(tmp_data); // boundary ( (width - half_mask_width) -> (width - 1) ) //----- calculate the tempotary array int ltmp = 2 * half_mask_width; for(k = 0; k < ltmp; k ++) tmp[k] = _DT(input_data, i, width - ltmp); for(k = ltmp; k < tmp_num; k ++) tmp[k] = _DT(input_data, i, k - ltmp); //----- claculate the pixel on the right boundary for(j = width - half_mask_width; j < width; j ++) _CalBoundary(tmp_data); } //--------------------- END OF CONVOLUTION WITH THE HORIZONAL MASK ------- //-------------- CONVOLUTION WITH THE VERTICAL MASK ----------------- // calculate Y-direction smoothed values of the main body of the image for(int j = 0; j < width; j ++) for(int i = half_mask_width; i < height - half_mask_width; i ++) { double sum_pixel = 0.0; for(int k = 0; k < mask_width; k ++) sum_pixel += mask[k] * _DT(tmp_data, i + k - half_mask_width, j); _DT(output_data, i, j) =(int)(sum_pixel); } // calculate the Y-direction boundary smoothed pixels of the image for(j = 0; j < width; j ++) { // boundary ( Y: 0 -> half_mask_width ) //----- calculate the tempotary array for(int k = 0; k < half_mask_width; k ++) tmp[k] = _DT(input_data, height - half_mask_width + k, j); for(k = half_mask_width; k < tmp_num; k ++) tmp[k] = _DT(tmp_data, k - half_mask_width, j); //----- claculate the pixel on the bottom boundary for(int i = 0; i < half_mask_width; i ++) _CalBoundary(output_data); // boundary ( Y: (height - half_mask_width) -> (height - 1) ) //----- calculate the tempotary array int ltmp = 2 * half_mask_width; for(k = 0; k < ltmp; k ++) tmp[k] = _DT(tmp_data, height - ltmp, j); for(k = ltmp; k < tmp_num; k ++) tmp[k] = _DT(tmp_data, k - ltmp, j); //----- claculate the pixel on the top boundary for(i = height - half_mask_width; i < height; i ++) _CalBoundary(output_data); } //--------------------- END OF CONVOLUTION WITH THE VERTICAL MASK ------- delete tmp_data; } //----------------------------------------------------------- //Gauss1D(): computate the 1D Gauss mask matrix(计算一维高斯模板矩阵) //----------------------------------------------------------- void IMAGE2D::Gauss1D(double sigma, int mask_width, double *mask_matrix) { double sum_mask = 0.0; int half_width = (int)(mask_width - 1) / 2; for(int i = -half_width; i <= half_width; i ++) { double gx = exp(-(double)(i * i) / (2.0 * sigma * sigma)); mask_matrix[i + half_width] = gx; sum_mask += gx; } // Normalize the mask matrix for(i = -half_width; i <= half_width; i ++) mask_matrix[i + half_width] /= sum_mask; } //---------------------------------------------------------------------- // simpleThresholding(): One threshold is given as an input parameter. //---------------------------------------------------------------------- void IMAGE2D::simpleThresholding(int threshold, unsigned char *Data) { for(int i = 0; i < height; i ++) for(int j = 0; j < width; j ++) { if(_DT(Data, i, j) >= threshold) { _DT(Data, i, j) = 255; } else _DT(Data, i, j) = 0; } } //-------------------------------------------------------------------------------------- // simpleDoubleThresholding(): Up and down thresholds are given as two input parameters. // threshold1: down threshold, threshold2: up threshold //-------------------------------------------------------------------------------------- void IMAGE2D::simpleDoubleThresholding(unsigned char *Data, int threshold1, int threshold2) { for(int i = 0; i < height; i ++) for(int j = 0; j < width; j ++) { if(_DT(Data, i, j) >= threshold1 && _DT(Data, i, j) <= threshold2) _DT(Data, i, j) = 255; else _DT(Data, i, j) = 0; } } //--------------------------------------------------------------------------- // GlobalThresholding(): Threshold is selected according to top Percent% // of the pixels. //--------------------------------------------------------------------------- int IMAGE2D::GlobalThresholding(float percent, unsigned char *Data) { int threshold, sum = 0, num = 0; GenHistogram(Data); int topPixels = (int)(percent * 0.01 * width * height); for(int k = gray_level; k >= 0; k --) { sum += histogram[k]; if(sum >= topPixels) { threshold = k; break; } } for(int i = 0; i < height; i ++) for(int j = 0; j < width; j ++) { if(_DT(Data, i, j) >= threshold) { _DT(Data, i, j) = 255; num ++; } else _DT(Data, i, j) = 0; } return num; // Returned value } //// Begin: Thinning() ========================================== //--------------------------------------------------------------- // Thinning(): // Hilditch algrithm is the most common way for thinning // Use 8 neighbor link //--------------------------------------------------------------- void IMAGE2D::Thinning(unsigned char *inData) { int i,j, k; int s, nrn, xx, yy, x; unsigned char gray; unsigned char *tmpData = new unsigned char[height * width]; // Covert the original image data into the value 0 or 1: // 0--background pixel, 1-- edge pixel for(i = 0; i < height; i ++) for(j = 0; j< width; j ++) { gray = _DT(inData, i, j); if(gray == LinePixel) _DT(tmpData, i, j) = 1; if(gray == BackgdPixel) _DT(tmpData, i, j) = 0; _DT(inData, i, j) = _DT(tmpData, i, j); } do{ s=0; // if the pixel value is 3 (this pixel needs to be cleared), set the value to be 0 for(i = 0; i < height; i ++) { for(j = 0; j < width; j ++) { if(_DT(inData, i, j) == 3) _DT(inData, i, j) = 0; _DT(tmpData, i, j) = _DT(inData, i, j); } } CopyImage(inData, tmpData); // begin to scan the image for(i = 1; i < height - 1; i ++) { yy = i; for(j = 1; j < width - 1; j ++) { xx = j; // if pixel isn't 0, don't process it if(_DT(inData, i, j) != 1) continue; // if all pixels in 4 neightbor aren't 0, don't process it if((_DT(tmpData, i-1, j) * _DT(tmpData, i+1, j) * _DT(tmpData, i, j-1) * _DT(tmpData, i, j+1)) !=0) continue; // if the value of arround pixels nrn <=1, set the pixel value 2 (this pixel can't be cleared) nrn = _DT(tmpData, yy-1, xx-1) + _DT(tmpData, yy-1, xx) + _DT(tmpData, yy-1, xx+1) + _DT(tmpData, yy, xx-1) + _DT(tmpData, yy, xx+1) + _DT(tmpData, yy+1, xx-1) + _DT(tmpData, yy+1, xx) + _DT(tmpData, yy+1, xx+1); if(nrn <= 1) { _DT(inData, i, j) = 2; continue; } CalCrossNumber(inData, xx, yy, &x, &k); // if cross number x isn't 1, set the pixel value to be 2 if( x != 1) { _DT(inData, i, j) = 2; continue; } if(_DT(inData, i-1, j) == 3) { _DT(inData, i-1, j) = 0; CalCrossNumber(inData, xx, yy, &x, &k); // if the cross number isn't 1, set the up neightbor pixel to be 3 if(x != 1) { _DT(inData, i-1, j) = 3; continue; } _DT(inData, i-1, j) = 3; } if(_DT(inData, i, j-1) != 3) { _DT(inData, i, j) = 3; s=1; continue; } _DT(inData, i, j-1) = 0; CalCrossNumber(inData, xx, yy, &x, &k); if(x==1) { _DT(inData, i, j-1) = 3; _DT(inData, i, j) = 3; s=1; } else _DT(inData, i, j-1) = 3; } } // if have no other pixel needs to be processed, end scanning if( s==0) break; }while(1); for(i=0; i = height - half_sizeY || j < half_sizeX || j >= width - half_sizeX) _DT(outData, i, j) = 0; else { ConvolveOnePixel(sizeX, sizeY, Sx, i, j, &pixelX, inData); ConvolveOnePixel(sizeX, sizeY, Sy, i, j, &pixelY, inData); _DT(tmpdata, i, j) = _INT_SQRT(pixelX, pixelY); if( _DT(tmpdata, i, j) > max) max = _DT(tmpdata, i, j); } } // ---- scaling float scale = 1.0f; if(max > 255) scale = 255.f / (float)max; else scale = (float)max / 255.f; for(i = 0; i < height; i ++) for( int j = 0; j < width; j ++) _DT(outData, i, j) = (unsigned char)(_DT(tmpdata, i, j) * scale); delete tmpdata; } //// Begin: CannyEdgeDetector() ========================================== //-------------------------------------------------------------------- // CannyEdgeDetector(): the first drivative of Guaussian Edge Detector // // | -1 1 | // Sx = | -1 1 | // // | 1 1 | // Sy = | -1 -1 | //-------------------------------------------------------------------- void IMAGE2D::CannyEdgeDetector(int mask_width, double sigma, unsigned char *inData, unsigned char *outData) { static int Sx[] = {-1, 1, -1, 1}; static int Sy[] = { 1, 1, -1, -1}; static int sizeX = 2, sizeY = 2; GaussSmooth(sigma, mask_width, inData, outData); CopyImage(outData, inData); int *tmpdata = new int[width*height]; int max = 0; // calculate values of the main body of the image int pixelX, pixelY; theta = new int[width * height]; for(int i = 0; i < height - 1; i ++) for(int j = 0; j < width - 1; j ++) { ConvolveOnePixel(sizeX, sizeY, Sx, i, j, &pixelX, inData); ConvolveOnePixel(sizeX, sizeY, Sy, i, j, &pixelY, inData); // Compute the magnitude _DT(outData, i, j) = _INT_SQRT(pixelX, pixelY); _DT(tmpdata, i, j) = _INT_SQRT(pixelX, pixelY); if( _DT(tmpdata, i, j) > max) max = _DT(tmpdata, i, j); // Compute the orientation if(pixelX == 0) { if( pixelY == 0) _DT(theta, i, j) = 0; else if(pixelY > 0) _DT(theta, i, j) = (int)(ZOOMIN * PI / 2.0f); else _DT(theta, i, j) = (int)(- ZOOMIN * PI / 2.0f); } else _DT(theta, i, j) = (int)(ZOOMIN * atanf((float)pixelY/(float)pixelX)); } // ---- scaling float scale = 1.0f; if(max > 255) scale = 255 / (float)max; for(i = 0; i < height; i ++) for( int j = 0; j < width; j ++) _DT(outData, i, j) = (unsigned char)(_DT(tmpdata, i, j) * scale); NonmaxSuppression(outData); int half_size = (mask_width - 1) / 2; for(i = 0; i < height; i ++) for(int j = 0; j < width; j ++) // clear to be 0 on the boundary if(i < half_size || i >= height - half_size || j < half_size || j >= width - half_size) _DT(outData, i, j) = 0; else continue; delete tmpdata; } //-------------------------------------------------------------------------- // NonmaxSuppression(): Nonmaxima suppresion thins the ridges of gradient // (Canny algorithms) magnitude by suppressing all values along the line // of the gradient that are not peak values of a ridge. //-------------------------------------------------------------------------- void IMAGE2D::NonmaxSuppression(unsigned char * input_data) { int i1, i2, j1, j2; for(int i = 1; i < height - 1; i ++) for(int j = 1; j < width - 1; j ++) { FindOrientNeighbors(i, j, &i1, &j1, &i2, &j2); if(_DT(input_data, i, j) <= _DT(input_data, i1, j1) && _DT(input_data, i, j) <= _DT(input_data, i2, j2)) _DT(input_data, i, j) = 0; } delete theta; } //-------------------------------------------------------------------------- // FindOrientNeighbors(): Find two neighbors of center pixel along its // (Canny algorithms) orientation within the 3x3 neighborhood. //-------------------------------------------------------------------------- void IMAGE2D::FindOrientNeighbors(int i0, int j0, int *i1, int *j1, int *i2, int *j2) { float PI_8 = (float)(ZOOMIN * PI) / 8.0f; float PI_4 = (float)(ZOOMIN * PI) / 4.0f; float PI_2 = (float)(ZOOMIN * PI) / 2.0f; float angle = (float)(_DT(theta, i0, j0)); if(angle >= - PI_8 && angle < PI_8 || angle >= PI - PI_8 && angle < PI + PI_8) { *i1 = i0 + 1; *j1 = j0; *i2 = i0 - 1; *j2 = j0; } else if(angle >= PI_8 && angle < PI_4 + PI_8 || angle >= - PI + PI_8 && angle < - PI_2 - PI_8) { *i1 = i0 + 1; *j1 = j0 + 1; *i2 = i0 - 1; *j2 = j0 - 1; } else if(angle >= PI_2 - PI_8 && angle < PI_2 + PI_8 || angle >= - PI_2 - PI_8 && angle < - PI_2 + PI_8) { *i1 = i0; *j1 = j0 + 1; *i2 = i0; *j2 = j0 - 1; } else { *i1 = i0 - 1; *j1 = j0 + 1; *i2 = i0 + 1; *j2 = j0 - 1; } } //// End of CannyEdgeDetector() ==================================== //--------------------------------------------------------------- // ConvolveOnePixel(): Convolution for one pixel: ImgData[i,j] //--------------------------------------------------------------- void IMAGE2D::ConvolveOnePixel(int sizeX, int sizeY, int* mask, int i, int j, int* pixel_value, unsigned char* inData) { int half_sizeX = (sizeX - 1) / 2; int half_sizeY = (sizeY - 1) / 2; // calculate values of the main body of the image int sum = 0; for(int n = 0; n < sizeY; n ++) for(int m = 0; m < sizeX; m ++) sum += mask[n * sizeX + m] * _DT(inData, i - half_sizeY + n, j - half_sizeX + m); *pixel_value = sum; } //// Begin: HoughTransform() =========================================== //---------------------------------------------------------------------- // HoughTransform(): // line representation: p = x * cos(theta) + y * sin(theta) //---------------------------------------------------------------------- void IMAGE2D::HoughTransform(unsigned char *inData, float bins) { // Thresholding first (Two values) //---- For displaying accumulator (rtData) ---------------------------- int roh_num = (int)(height / bins); // the number of divided roh int theta_num =(int)( width / bins); // the number of divided theta unsigned char *rtData = new unsigned char[height * width]; ClearImage(rtData); // set the diagonal of the original image to be the maxium of p rohmax =2 * (float)sqrt((float) width*width + (float) height*height); Hough_width = Hough_height = (int)(rohmax / bins + 0.5f); HoughData = new unsigned int[Hough_height * Hough_width]; // Clear to be 0 for(int i = 0; i < Hough_height; i ++) for( int j = 0; j < Hough_width; j ++) HoughData[i * Hough_width + j] = 0; float theta, roh; int pre_r = 0, pre_roh = 0, rohi; for(int y = 0; y < height; y ++) for(int x = 0; x < width; x ++) { // if the pixel value is a background pixel, continue if(_DT(inData, y, x) == BackgdPixel) continue; //x*cos(theta)+y*sin(theta)-p=0 //theta=[-PI, PI), p=(-rohmax, rohmax) // ---- for HoughData -------- for(int t = 0; t < Hough_width; t ++) { //theta=[-PI,PI) theta = (float)((2 * (float)t / Hough_width - 1) * PI); roh =(float)(x*cos(theta) + y*sin(theta)); rohi = (int)(roh*Hough_height/rohmax + Hough_height/2 + 0.5f); HoughData[rohi * Hough_width + t] ++; if(t > 0) { int droh = rohi - pre_roh; int sym = 1; if(droh<0) sym = -1; if(abs(droh) > 1) { for(int n = 1; n < abs(droh) ; n ++) if(n <= abs(droh/2)) HoughData[(pre_roh + n*sym) * Hough_width + t - 1] ++; else HoughData[(pre_roh + n*sym) * Hough_width + t] ++; } } pre_roh = rohi; } //----- for rtData ----- for(t = 0; t < theta_num; t ++) { //theta=[-PI,PI) theta = (float)((2 * (float)t / theta_num - 1) * PI); roh =(float)(x*cos(theta) + y*sin(theta)); int r = (int)((roh + rohmax/2)*(float)roh_num/rohmax + 0.5f); _DT(rtData, r, t) ++; if(t > 0) { int dr = r - pre_r; int sym = 1; if(dr<0) sym = -1; if(abs(dr) > 1) { for(int n = 1; n < abs(dr) ; n ++) if(n <= abs(dr/2)) _DT(rtData, pre_r + n*sym, t - 1) ++; else _DT(rtData, pre_r + n*sym, t) ++; } } pre_r = r; } } CopyImage(rtData, inData); delete rtData; } //// End of HoughTransform() =========================================== //// Begin: LineFitting() ============================================== //---------------------------------------------------------------------- // LineFitting(): //---------------------------------------------------------------------- void IMAGE2D::LineFitting(unsigned char *inData, float thresh_percent) { int threshold; int num_peaks = PeakDetection(inData, thresh_percent, &threshold); int *peaks = new int[2*num_peaks]; int numOfPeaks = GetPeaks(threshold, num_peaks, peaks); numOfPeaks = PeakFitting(numOfPeaks, peaks); // new peaks BackProjection(inData, peaks, numOfPeaks); } //---------------------------------------------------------------------- // BackProjection(): //---------------------------------------------------------------------- void IMAGE2D::BackProjection(unsigned char *outData, int *peaks, int numOfPeaks) { ClearImage(outData); // --- Calculate the (x,y) along X-axi for(int x = 0; x < width; x ++) for( int n = 0; n < numOfPeaks; n ++) { // theta=[-PI, PI) float theta = (float)(2* PI * (float)peaks[n] / Hough_width - PI); float roh = ((float)peaks[numOfPeaks + n]/Hough_height -0.5f)* rohmax; int yy = (int)((roh - x * cos(theta)) / sin(theta)); if(yy >= 0 && yy < height) _DT(outData, yy, x) = LinePixel; } // Calculate the (x,y) along Y-axi for(int y = 0; y < height; y ++) for( int n = 0; n < numOfPeaks; n ++) { // theta=[-PI, PI) float theta = (float)(2* PI * (float)peaks[n] / Hough_width - PI); float roh = ((float)peaks[numOfPeaks + n]/Hough_height -0.5f)* rohmax; int xx = (int)((roh - y * sin(theta)) / cos(theta)); if(xx >= 0 && xx < width) _DT(outData, y, xx) = LinePixel; } } //---------------------------------------------------------------------- // PeakFitting(): return the number of new peaks //---------------------------------------------------------------------- int IMAGE2D::PeakFitting(int numOfPeaks, int *peaks) { int dx, dy; dx = dy = 5; float rohmax = 2 * (float)sqrt((float) width*width + (float) height*height); int theta_num = (int)(rohmax + 0.5f); int *newX = new int[numOfPeaks]; int *newY = new int[numOfPeaks]; newX[0] = peaks[0]; newY[0] =peaks[numOfPeaks]; int newNum = 1, flag; for(int n = 1; n < numOfPeaks; n ++) { int curX = peaks[n]; int curY = peaks[numOfPeaks + n]; flag = 0; for(int m = 0; m < newNum; m ++) { // If similar, calculate their average value if(abs(curX - newX[m]) <= dx && abs(curY - newY[m]) <= dy) { if(abs(curX - theta_num/2) < dx) // theta = 0 newX[m] = theta_num/2; else if(abs(curX - theta_num/4) < dx) // theta = -PI/2 newX[m] = theta_num / 4; else if(abs(curX - theta_num*3/4) < dx) // theta = PI/2 newX[m] = theta_num * 3 / 4; else newX[m] =(int)((newX[m] + curX) / 2.0f + 0.5); newY[m] = (int)((newY[m] + curY) / 2.0f + 0.5); flag = 1; } } if(flag == 0) // not found the similar peak { newX[newNum] = curX; newY[newNum] = curY; newNum ++; } } for(int i = 0; i < newNum; i ++) { peaks[i] = newX[i]; peaks[i + newNum] = newY[i]; } return newNum; } //---------------------------------------------------------------------- // GetPeaks(): //---------------------------------------------------------------------- int IMAGE2D::GetPeaks(int threshold, int numOfPeaks, int *peaks) { int num = 0; int width1 = (int)((float)Hough_width/4.0f); int width2 = (int)((float)Hough_width*3.0f/4.0f); int * peakX = new int[numOfPeaks]; int * peakY = new int[numOfPeaks]; for(int i = 0; i < Hough_height; i ++) for(int j = width1; j < width2; j ++) // theta=[-PI/2, PI/2) if(HoughData[i * Hough_width + j] >= (unsigned int)threshold) { peakY[num] = i; // roh peakX[num] = j; // theta num ++; } numOfPeaks = num; for( int k = 0; k < numOfPeaks; k ++) { peaks[numOfPeaks + k] = peakY[k]; peaks[k] = peakX[k]; } return numOfPeaks; } //---------------------------------------------------------------------- // PeakDetection(): //---------------------------------------------------------------------- int IMAGE2D::PeakDetection(unsigned char * inData, float percent, int *threshold) { //Peak detection (Thresholding algorithm similar to global thresholding algoroghtm) unsigned int * hist = new unsigned int[gray_level + 1]; hist = GetHistogram(HoughData, Hough_width, Hough_height); int sum = 0; int topPixels = (int)(percent * 0.01 * ( Hough_width * Hough_height - hist[0])); for(int k = gray_level; k > 0; k --) // except k = 0 { sum += hist[k]; if(sum >= topPixels) { *threshold = k; break; } } int numOfPeaks = sum; return numOfPeaks; } //// End of LineFitting() ============================================== //// Begin: Image tools =================================== //--------------------------------------------------------- // NegativeImage(): Make the image to be negative image //--------------------------------------------------------- void IMAGE2D::NegativeImage(unsigned char *data) { for(int i = 0; i < height; i ++) for(int j = 0; j < width; j ++) _DT(data, i, j) = gray_level - _DT(data, i, j); } //--------------------------------------------- // FlipImage(): Filp the image along the X axis //--------------------------------------------- void IMAGE2D::FlipImage(unsigned char *data) { tmp_data = new unsigned char[width * height]; CopyImage(data, tmp_data); for(int i = 0; i < height; i ++) for(int j = 0; j < width; j ++) _DT(data, i, j) = _DT(tmp_data, height - i, j); delete tmp_data; } //--------------------------------------------------------- // CopyImage(): Copy one image to another image //--------------------------------------------------------- void IMAGE2D::CopyImage(unsigned char *srcData, unsigned char *data) { for(int i = 0; i < height; i ++) for(int j = 0; j < width; j ++) data[i * width + j] = srcData[i * width + j]; } //--------------------------------------------------------- // ClearImage(): Clear image to be 0 //--------------------------------------------------------- void IMAGE2D::ClearImage(unsigned char *data) { for(int i = 0; i < height; i ++) for(int j = 0; j < width; j ++) data[i*width+j] = 0; } //--------------------------------------------------------- // BlendImage(): Combine two images into one image //--------------------------------------------------------- void IMAGE2D::BlendImage(unsigned char *srcData, unsigned char *data) { for(int i = 0; i < height; i ++) for(int j = 0; j < width; j ++) data[i*width+j] |= srcData[i*width+j]; } // ************************************************************************ // // 图像形态学变换函数 // // ErosionGrayImage() - 图像腐蚀 // DilationGrayImage() - 图像膨胀 // OpenGrayImage() - 图像开运算 // CloseGrayImage() - 图像闭运算 // // ************************************************************************ /************************************************************************* * * 函数名称: * ErosionGrayImage() * * 参数: * const unsigned char *srcData - 指向源图像指针 * unsigned char *dstData - 指向目标图像的指针 * int element[2][2] - 结构元数组 * * 返回值: * BOOL - 腐蚀成功返回TRUE,否则返回FALSE。 * * 说明: * 该函数用于对图像进行腐蚀运算。 * 目标图像为灰度图像。 ************************************************************************/ BOOL IMAGE2D::ErosionGrayImage(unsigned char *srcData, unsigned char *dstData, int element[2][2]) { int i,j; int m=height,n=width; unsigned char gray; for(i=0;i t) j--; x[i]=x[j]; while (i graylevel2) { w = 2 * (graylevel1 - graylevel2); } else { w = 2 * (graylevel2 - graylevel1); } if(h_fre1 == h && h_fre2 == h) { m = 1; } else { m = 2; } } void IMAGE2D::GradientAmplitudeHistogram(unsigned char *WndData)//产生梯度幅度直方图 { int i,j; //计算图像上各灰度级对应的灰度梯度幅度值 for(i = 0; i < ScoutWndWidth; i++) { for(j = 0; j < ScoutWndHeight; j++) { gray[i * ScoutWndWidth + j] = WndData[i * ScoutWndWidth +j]; GradsAmp[gray[i * width + j]] = sqrt((gray[i * ScoutWndWidth + j] - gray[(i + 1) * ScoutWndWidth+ j]) * (gray[i * ScoutWndWidth + j] - gray[(i + 1) * ScoutWndWidth + j]) + (gray[i * ScoutWndWidth + j] - gray[i * ScoutWndWidth + j + 1]) * (gray[i *ScoutWndWidth + j] - gray[i * ScoutWndWidth + j + 1])); } } //产生灰度梯度幅度直方图(统计各灰度级值的梯度幅度(大小)的分布情况) //计算背景的灰度梯度幅度均值和均方差 double sum_GradsAmp1 = sum_element(GradsAmp,gray_level1); for(i = 0;i < gray_level1; i++) { pr1[i] = (GradsAmp[i])/(sum_GradsAmp1); part1[i] = GrayLevel[i] * pr1[i]; } m_GA1 = sum_element(part1,gray_level1); for(i = 0; i < gray_level1; i++) { part_MSE1[i] = (part1[i] - m_GA1) * (part1[i] - m_GA1); } double sum_MSEGA1 = sum_element(part_MSE1,gray_level1); MSE_GA1 = sqrt(sum_MSEGA1/(gray_level1 - 1)); //计算目标的灰度梯度幅度均值和均方差 int n = graylevel - gray_level2; double sum_GradsAmp2 = sum_element(GradsAmp,n); for(i = gray_level2;i < graylevel; i++) { pr1[i] = (GradsAmp[i])/(sum_GradsAmp2); part1[i] = GrayLevel[i] * pr1[i]; } m_GA2 = sum_element(part1,n); for(i = gray_level2; i < graylevel; i++) { part_MSE1[i] = (part1[i] - m_GA2) * (part1[i] - m_GA2); } double sum_MSEGA2 = sum_element(part_MSE1,n); MSE_GA2 = sqrt(sum_MSEGA2/(n - 1)); //generate the gray gradient amplitude histogram of the input image for(i = 0; i < graylevel; i ++) { x[i] = -(i-m_GA1)*(i-m_GA1)/((MSE_GA1*MSE_GA1)*2); Math_GA1 = p1/(MSE_GA1*sqrt(2*PI)); GrayGA_fre1[i] = Math_GA1*(exp(x[i])); y[i] = -(i-m_GA2)*(i-m_GA2)/((MSE_GA2*MSE_GA2)*2); Math_GA2 = p2/(MSE_GA2*sqrt(2*PI)); GrayGA_fre2[i] = Math_GA2*(exp(x[i])); //产生高斯拟合灰度梯度幅度直方图 GradsAmp[i] = GrayGA_fre1[i] + GrayGA_fre2[i]; } //梯度幅度直方图的峰高和峰宽 h1_fre1 = max_element(GrayGA_fre1,gray_level1); h1_fre2 = max_element(GrayGA_fre2,n); h1 = max_element(GradsAmp,graylevel); graylevel11 = graylevel; min_element(GradsAmp,gray_level); graylevel12 = graylevel; if(graylevel11 > graylevel12) { w = 2 * (graylevel11 - graylevel12); } else { w = 2 * (graylevel12 - graylevel11); } if(h_fre1 == h && h_fre2 == h) { m = 1; } else { m = 2; } } void IMAGE2D::GradientDirectionHistogram(unsigned char *WndData) { int i,j; for(i = 0; i < ScoutWndWidth; i++) { for(j = 0; j < ScoutWndHeight; j++) { gray[i * ScoutWndWidth + j] = WndData[i * ScoutWndWidth +j]; GradsDirect[gray[i * ScoutWndWidth + j]] = (gray[i * ScoutWndWidth + j] - gray[i * ScoutWndWidth + j + 1]) /(gray[i * ScoutWndWidth + j] - gray[(i + 1) * ScoutWndWidth + j]); } } //产生灰度梯度方向直方图(统计各灰度级值的梯度方向的分布情况) //计算背景的灰度梯度方向均值和均方差 double sum_GradsDirect1 = sum_element(GradsDirect,gray_level1); for(i = 0;i < gray_level1; i++) { pr2[i] = (GradsDirect[i])/(sum_GradsDirect1); part2[i] = GrayLevel[i] * pr2[i]; } m_GD1 = sum_element(part2,gray_level1); for(i = 0; i < gray_level1; i++) { part_MSE2[i] = (part2[i] - m_GD1) * (part2[i] - m_GD1); } double sum_MSEGD1 = sum_element(part_MSE2,gray_level1); MSE_GD1 = sqrt(sum_MSEGD1/(gray_level1 - 1)); //计算目标的灰度梯度方向均值和均方差 int n = graylevel - gray_level2; double sum_GradsDirect2 = sum_element(GradsDirect,n); for(i = gray_level2;i < graylevel; i++) { pr2[i] = (GradsDirect[i])/(sum_GradsDirect2); part2[i] = GrayLevel[i] * pr2[i]; } m_GD2 = sum_element(part2,n); for(i = gray_level2; i < graylevel; i++) { part_MSE2[i] = (part2[i] - m_GD2) * (part2[i] - m_GD2); } double sum_MSEGD2 = sum_element(part_MSE2,n); MSE_GD2 = sqrt(sum_MSEGD2/(n - 1)); MSE_GD = MSE_GD1 + MSE_GD2; // a1' = 1/MSE_GD; //generate the gray gradient amplitude histogram of the input image for(i = 0; i < graylevel; i ++) { x[i] = -(i-m_GD1)*(i-m_GD1)/((MSE_GD1*MSE_GD1)*2); Math_GD1 = p1/(MSE_GD1*sqrt(2*PI)); GrayGD_fre1[i] = Math_GD1*(exp(x[i])); y[i] = -(i-m_GD2)*(i-m_GD2)/((MSE_GD2*MSE_GD2)*2); Math_GD2 = p2/(MSE_GD2*sqrt(2*PI)); GrayGD_fre2[i] = Math_GD2*(exp(x[i])); //产生高斯拟合灰度梯度方向直方图 GradsDirect[i] = GrayGD_fre1[i] + GrayGD_fre2[i]; } //梯度方向直方图的峰高和峰宽 h2_fre1 = max_element(GrayGD_fre1,gray_level1); h2_fre2 = max_element(GrayGD_fre2,n); h2 = max_element(GradsDirect,graylevel); graylevel21 = graylevel; min_element(GradsDirect,graylevel); graylevel22 = graylevel; if(graylevel21 > graylevel22) { w = 2 * (graylevel21 - graylevel22); } else { w = 2 * (graylevel22 - graylevel21); } if(h_fre1 == h && h_fre2 == h) { m = 1; } else { m = 2; // if(w == 16) // { // a2' =1; //} // else if(w > 10 &&w !=16) // { // a2' = 0; // } //else //{ // a2' = 0.5; //} } } void IMAGE2D::BasicDollarScout(unsigned char *inData,int BasDolSize) { int j = BasDolSize; //定义基元搜索窗口的大小,并指定其初始位置 if(m_Parms.fMakeUserHitOKToScout == TRUE) m_Parms.iWindowHeight = BasDolSize + 5;//设置窗口的高度 m_Parms.iWindowWidth = 30;//inpixels,设置窗口的宽度 m_ScoStatus.x = 0; m_ScoStatus.y = 0;//窗口的初始位置 m_Parms.diScout = eLEFTtoRIGHT; int mNumberMax = (int)((width*height)/(m_Parms.iWindowWidth*m_Parms.iWindowHeight));//搜索窗口的最大值 //搜索窗口在影像上滑动,从第一个窗口开始道路基元的搜索 for(int i = 1; i <= mNumberMax; i++) { m_ScoStatus.x += 30; m_ScoStatus.y += (BasDolSize + 5); if(m_ScoStatus.fBeginScout = TRUE) { //判断梯度方向直方图是否存在对称双峰 for(; j >= BasDolSize - 10;j--) { for(int x = m_ScoStatus.x; x <= m_ScoStatus.x +30; x++) for(int y = m_ScoStatus.y; y <= m_ScoStatus.y+j; y++) { IMAGE2D::GradientDirectionHistogram(DolData); if(m == 1) { return; } else if(m == 2) { IMAGE2D::GaussFittingHistogram(DolData); if(m == 2) { return; } else if(m == 1) { IMAGE2D::GradientAmplitudeHistogram(DolData); if(m == 2) { return; } else if(m ==1 && h != 0) { m_ScoStatus.fScoutBasicDollar = TRUE; } } } } } } } } void IMAGE2D::RoadEdgeAffirm(unsigned char *SlipWinData) { } BOOL IMAGE2D::Write(CFile *pFile) { BITMAPFILEHEADER bmfh; // 设置文件头中文件类型为"BM" bmfh.bfType = 0x4d42; // 计算信息头和调色板的大小尺寸 int nSizeHdr = sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * m_nColorTableEntries; // 指定文件的大小 bmfh.bfSize = sizeof(BITMAPFILEHEADER) + nSizeHdr + m_dwSizeImage; //设置保留字 bmfh.bfReserved1 = bmfh.bfReserved2 = 0; //从文件头到实际的位图数据的偏移字节数(除了位图数据以外的前三部分之和) bmfh.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * m_nColorTableEntries; // 进行写操作 try { //文件头的写入 pFile->Write((LPVOID) &bmfh, sizeof(BITMAPFILEHEADER)); //信息头和调色板的写入 pFile->Write((LPVOID) m_lpBMIH, nSizeHdr); //实际位图数据的写入 pFile->Write((LPVOID) m_lpImage, m_dwSizeImage); } // 错误处理 catch(CException* pe) { pe->Delete(); AfxMessageBox("write error"); return FALSE; } // 返回 return TRUE; }