bool IPLGradientOperator::roberts(IPLImage* image) { static float rxf[2][2] = {{1.0,0},{0,-1.0}}; static cv::Mat rxKernel(2,2,CV_32FC1,rxf); static float ryf[2][2] = {{0,1.0},{-1.0,0}}; static cv::Mat ryKernel(2,2,CV_32FC1,ryf); int width = image->width(); int height = image->height(); // fast gradient int progress = 0; int maxProgress = height*width; notifyProgressEventHandler(-1); cv::Mat input; cv::Mat gX; cv::Mat gY; cvtColor(image->toCvMat(),input,CV_BGR2GRAY); filter2D(input,gX,CV_32F,rxKernel); filter2D(input,gY,CV_32F,ryKernel); for(int x=1; x<width; x++) { // progress notifyProgressEventHandler(100*progress++/maxProgress); for(int y=1; y<height; y++) { ipl_basetype gx = gX.at<cv::Vec<float,1>>(y,x).val[0] * FACTOR_TO_FLOAT ; ipl_basetype gy = gY.at<cv::Vec<float,1>>(y,x).val[0] * FACTOR_TO_FLOAT ; double phase = (gx!=0.0 || gy!=0.0 )? atan2( -gy, gx ) : 0.0; while( phase > 2.0 * PI ) phase -= 2.0 * PI; while( phase < 0.0 ) phase += 2.0 * PI; // phase 0.0-1.0 phase /= 2 * PI; _result->phase(x,y) = phase; _result->magnitude(x,y) = sqrt(gx*gx + gy*gy); } } return true; }
bool IPLGradientOperator::fastGradient(IPLImage* image) { int width = image->width(); int height = image->height(); // fast gradient int progress = 0; int maxProgress = height*width; for(int x=1; x<width; x++) { // progress notifyProgressEventHandler(100*progress++/maxProgress); for(int y=1; y<height; y++) { double Dx = image->plane(0)->p(x,y) - image->plane(0)->p(x-1, y); double Dy = image->plane(0)->p(x,y) - image->plane(0)->p(x, y-1); double magnitude = sqrt( Dx * Dx + Dy * Dy ); double phase = (Dx!=0.0 || Dy!=0.0 )? atan2( -Dy, Dx ) : 0.0; while( phase > 2.0 * PI ) phase -= 2.0 * PI; while( phase < 0.0 ) phase += 2.0 * PI; // phase 0.0-1.0 phase /= 2 * PI; _result->phase(x,y) = phase; _result->magnitude(x,y) = magnitude; } } return true; }
bool IPLCompassMask::processInputData(IPLImage* image , int, bool) { // delete previous result delete _result; _result = NULL; int width = image->width(); int height = image->height(); _result = new IPLImage( image->type(), width, height ); // get properties int maskType = getProcessPropertyInt("maskType"); int direction = getProcessPropertyInt("direction"); int progress = 0; int maxProgress = image->height() * image->getNumberOfPlanes(); int nrOfPlanes = image->getNumberOfPlanes(); int startDir = ( direction == 8 )? 0 : direction; int endDir = ( direction == 8 )? 7 : direction+1; #pragma omp parallel for for( int planeNr=0; planeNr < nrOfPlanes; planeNr++ ) { IPLImagePlane* plane = image->plane( planeNr ); IPLImagePlane* newplane = _result->plane( planeNr ); { for(int y=0; y<height; y++) { // progress notifyProgressEventHandler(100*progress++/maxProgress); for(int x=0; x<width; x++) { int dirCount = 0; long sum = 0; long total = 0; for( int dir = startDir; dir<endDir; dir++ ) { dirCount++; sum = 0; for( int kx=-1; kx<=1; kx++ ) { for( int ky=-1; ky<=1; ky++ ) { int mask = _mask[maskType][dir][ky+1][kx+1]; sum += (long) (plane->cp(x+kx, y+ky) * FACTOR_TO_UCHAR) * (long) mask; } } total += sum; } total /= dirCount; total += 128; total = (total>255)? 255 : (total<0)? 0 : total; newplane->p(x,y) = total * FACTOR_TO_FLOAT; } } } } return true; }
bool IPLUndistort::processInputData(IPLImage* image, int, bool) { // get properties float k1 = getProcessPropertyDouble("k1"); float k2 = getProcessPropertyDouble("k2"); float k3 = getProcessPropertyDouble("k3"); float p1 = getProcessPropertyDouble("p1"); float p2 = getProcessPropertyDouble("p2"); float c1 = getProcessPropertyInt("f"); float c2 = c1; notifyProgressEventHandler(-1); cv::Mat cameraMatrix = (cv::Mat_<double>(3,3) << c1, 0, image->width()*0.5, 0, c2, image->height()*0.5, 0, 0, 1); cv::Mat distCoeffs(5, 1, CV_32FC1); distCoeffs.at<float>(0,0) = k1; distCoeffs.at<float>(1,0) = k2; distCoeffs.at<float>(2,0) = p1; distCoeffs.at<float>(3,0) = p2; distCoeffs.at<float>(4,0) = k3; cv::Mat result; cv::undistort(image->toCvMat(), result, cameraMatrix, distCoeffs); delete _result; _result = new IPLImage(result); return true; }
bool IPLGradientOperator::sobel(IPLImage* image) { int width = image->width(); int height = image->height(); const int kSize = 3; // fast gradient int progress = 0; int maxProgress = height*width; notifyProgressEventHandler(-1); cv::Mat input; cv::Mat gX; cv::Mat gY; cvtColor(image->toCvMat(),input,CV_BGR2GRAY); Sobel(input,gX,CV_32F,1,0,kSize); Sobel(input,gY,CV_32F,0,1,kSize); for(int x=1; x<width; x++) { for(int y=1; y<height; y++) { // progress notifyProgressEventHandler(100*progress++/maxProgress); ipl_basetype gx = gX.at<cv::Vec<float,1>>(y,x).val[0] * FACTOR_TO_FLOAT ; ipl_basetype gy = gY.at<cv::Vec<float,1>>(y,x).val[0] * FACTOR_TO_FLOAT ; double phase = (gx!=0.0 || gy!=0.0 )? atan2( -gy, gx ) : 0.0; while( phase > 2.0 * PI ) phase -= 2.0 * PI; while( phase < 0.0 ) phase += 2.0 * PI; phase /= 2.0 * PI; _result->phase(x,y) = phase; _result->magnitude(x,y) = sqrt(gx*gx + gy*gy); } } return true; }
bool IPLIFFT::processInputData(IPLImage* data , int, bool) { IPLComplexImage* complexImageData = data->toComplexImage(); if (NULL == complexImageData) { // TODO write an error message return false; } _complexImage = new IPLComplexImage(*complexImageData); // delete previous result delete _result; _result = NULL; int width = _complexImage->width(); int height = _complexImage->height(); _result = new IPLImage(IPL_IMAGE_GRAYSCALE, width, height); // get properties //int mode = getProcessPropertyInt("mode"); int progress = 0; int maxProgress = height; _complexImage->IFFT(); float dc = _complexImage->real(0,0); float min = _complexImage->minReal(); float max = _complexImage->maxReal(); float diff = max-min; for(int y=0; y<height; y++) { // progress notifyProgressEventHandler(100*progress++/maxProgress); for(int x=0; x<width; x++) { float value = (_complexImage->real(x,y) - min) / diff; value = (value < 0) ? 0 : value; value = (value > 1) ? 1 : value; _result->plane(0)->p(x, y) = value; } } std::stringstream s; s << "DC: "; s << dc; addInformation(s.str()); return true; }
void IPLMorphologyHitMiss::hitmiss(IPLImagePlane* workingPlane, IPLImagePlane* resultPlane) { int kernelOffset = (int)sqrt((float)_kernel.size()) / 2; int width = workingPlane->width(); int height = workingPlane->height(); for(int y=0; y<height; y++) { // progress notifyProgressEventHandler(100*_progress++/_maxProgress); for(int x=0; x<width; x++) { int i = 0; bool success = true; for( int ky=-kernelOffset; ky<=kernelOffset && success; ky++ ) { for( int kx=-kernelOffset; kx<=kernelOffset && success; kx++ ) { if(i >= (int) _kernel.size()) continue; int kernelValue = _kernel[i++]; int r = x+kx; int c = y+ky; if(kernelValue > -1) if(kernelValue != (workingPlane->bp(r,c) ? 1 : 0)) success = false; // breaks both for loops } } if(success) resultPlane->p(x,y) = 1.0f; } } }
bool IPLCanvasSize::processInputData(IPLImage* image , int, bool) { // delete previous result delete _result; _result = NULL; int width = image->width(); int height = image->height(); _result = new IPLImage(image->type(), width, height); // get properties int new_width = getProcessPropertyInt("width"); int new_height = getProcessPropertyInt("height"); IPLColor color = getProcessPropertyColor("color"); int anchor = getProcessPropertyInt("anchor"); _result = new IPLImage(image->type(), new_width, new_height); int progress = 0; int maxProgress = image->height() * image->getNumberOfPlanes(); int nrOfPlanes = _result->getNumberOfPlanes(); //Anchor:Top Left|Top|Top Right|Left|Center|Right|Bottom Left|Bottom|Bottom Right // Top Left int offset_x = 0; int offset_y = 0; if(anchor == 1) { // Top offset_x = (new_width-width) * 0.5; offset_y = 0; } else if(anchor == 2) { // Top Right offset_x = new_width-width; offset_y = 0; } else if(anchor == 3) { // Left offset_x = 0; offset_y = (new_height-height) * 0.5; } else if(anchor == 4) { // Center offset_x = (new_width-width) * 0.5; offset_y = (new_height-height) * 0.5; } else if(anchor == 5) { // Right offset_x = new_width-width; offset_y = (new_height-height) * 0.5; } else if(anchor == 6) { // Bottom Left offset_x = 0; offset_y = new_height-height; } else if(anchor == 7) { // Bottom offset_x = (new_width-width) * 0.5; offset_y = new_height-height; } else if(anchor == 8) { // Bottom Right offset_x = new_width-width; offset_y = new_height-height; } if(nrOfPlanes == 1) { addWarning("For grayscale images, the red slider is used as background value."); } #pragma omp parallel for for( int planeNr=0; planeNr < nrOfPlanes; planeNr++ ) { IPLImagePlane* plane = image->plane( planeNr ); IPLImagePlane* newplane = _result->plane( planeNr ); ipl_basetype background = 0.0; if(planeNr == 0) background = color.red(); else if(planeNr == 1) background = color.green(); if(planeNr == 2) background = color.blue(); for(int y=0; y<new_height; y++) { // progress notifyProgressEventHandler(100*progress++/maxProgress); for(int x=0; x<new_width; x++) { int from_x = x - offset_x; int from_y = y - offset_y; // check if inside source image if(from_x < 0 || from_y < 0 || from_x > plane->width() || from_y > plane->height()) { newplane->p(x, y) = background; } else { newplane->p(x, y) = plane->p(from_x, from_y); } } } } return true; }
bool IPLBinarizeSavola::processInputData(IPLImage* image , int, bool) { // delete previous result delete _result; _result = NULL; int width = image->width(); int height = image->height(); _result = new IPLImage(image->type(), width, height); // get properties int window = getProcessPropertyInt("window"); double aboveMean = getProcessPropertyDouble("aboveMean"); IPLImage* mean = new IPLImage(image->type(), width, height); IPLImage* deviation = new IPLImage(image->type(), width, height); int progress = 0; int maxProgress = image->height() * image->getNumberOfPlanes(); int nrOfPlanes = image->getNumberOfPlanes(); #pragma omp parallel for for( int planeNr=0; planeNr < nrOfPlanes; planeNr++ ) { IPLImagePlane* plane = image->plane( planeNr ); IPLImagePlane* newplane = _result->plane( planeNr ); int w2 = window/2; float area = (float)(w2*2)*(float)(w2*2); float minI = FLT_MAX; float maxDeviation = 0.0; for(int y=0; y<height; y++) { // progress notifyProgressEventHandler(100*progress++/maxProgress); for(int x=0; x<width; x++) { if( plane->p(x,y) < minI ) minI = plane->p(x,y); float localMean = 0.0; for( int kx=-w2; kx<=w2; kx++ ) { for( int ky=-w2; ky<=w2; ky++ ) { localMean += (float)plane->cp(x+kx,y+ky); } } localMean /= area; mean->plane(planeNr)->p(x,y) = localMean; float dev = 0.0; for( int kx=-w2; kx<=w2; kx++ ) { for( int ky=-w2; ky<=w2; ky++ ) { float diff = (float)plane->cp(x+kx, y+ky) - localMean; dev += diff * diff; } } dev = sqrt( dev / area ); deviation->plane(planeNr)->p(x,y) = dev; if( dev > maxDeviation ) maxDeviation = dev; } for(int x=w2; x<width-w2; x++) { for(int y=w2; y<height-w2; y++) { float alpha = 1.0 - deviation->plane(planeNr)->p(x,y) / maxDeviation; int T = (int) ( mean->plane(planeNr)->p(x,y) - aboveMean * alpha *( mean->plane(planeNr)->p(x,y) - minI ) ); newplane->p(x,y) = ( plane->p(x,y) >= T ) ? 0.0 : 1.0; } } } } return true; }
bool IPLHarrisCorner::processInputData(IPLImage* image , int, bool useOpenCV) { // delete previous result delete _result; _result = NULL; int width = image->width(); int height = image->height(); _result = new IPLImage( image->type(), width, height ); // get properties int threshold = getProcessPropertyInt("threshold"); /*double sigma = getProcessPropertyDouble("sigma"); double lowThreshold = getProcessPropertyDouble("lowThreshold"); double highThreshold = getProcessPropertyDouble("highThreshold");*/ /*std::stringstream s; s << "Window: "; s << window; addInformation(s.str());*/ notifyProgressEventHandler(-1); cv::Mat input; cv::Mat output; cvtColor(image->toCvMat(), input, CV_BGR2GRAY); /// Detector parameters int blockSize = 2; int apertureSize = 3; double k = 0.04; cv::Mat dst_norm; /// Detecting corners cv::cornerHarris(input, output, blockSize, apertureSize, k, cv::BORDER_DEFAULT ); /// Normalizing cv::normalize( output, dst_norm, 0, 255, cv::NORM_MINMAX, CV_32FC1, cv::Mat() ); cv::convertScaleAbs( dst_norm, output ); cvtColor(output, output, CV_GRAY2BGR); /// Drawing a circle around corners for( int j = 0; j < dst_norm.rows ; j++ ) { for( int i = 0; i < dst_norm.cols; i++ ) { if( (int) dst_norm.at<float>(j,i) > threshold ) { cv::line(output, cv::Point(i-3, j), cv::Point(i+3, j), cv::Scalar(0,0,255)); cv::line(output, cv::Point(i, j-3), cv::Point(i, j+3), cv::Scalar(0,0,255)); } } } delete _result; _result = new IPLImage(output); return true; }
bool IPLFFT::processInputData(IPLImage* image , int, bool) { // delete previous result delete _result; _result = NULL; int width = image->width(); int height = image->height(); int cWidth = IPLComplexImage::nextPowerOf2(width); int cHeight = IPLComplexImage::nextPowerOf2(height); int size = cHeight = cWidth = (cWidth>cHeight)? cWidth : cHeight; _result = new IPLComplexImage(cWidth, cHeight); // get properties int mode = getProcessPropertyInt("mode"); int progress = 0; int maxProgress = image->height() * image->getNumberOfPlanes(); // image center int dx = ( cWidth - width )/2; int dy = ( cHeight - height )/2; IPLImagePlane* plane = image->plane(0); for(int y=0; y<height; y++) { // progress notifyProgressEventHandler(100*progress++/maxProgress); for(int x=0; x<width; x++) { _result->c(x+dx, y+dy) = Complex(plane->p(x,y), 0.0); } } // windowing function switch(mode) { case 0: // rectangular break; case 1: // Hanning for( int y=0; y<size; y++ ) for( int x=0; x<size; x++ ) _result->c(x,y) *= Hanning(x, size) * Hanning(y, size); break; case 2: // Hamming for( int y=0; y<size; y++ ) for( int x=0; x<size; x++ ) _result->c(x,y) *= Hamming(x, size) * Hamming(y, size); break; case 3: // Blackman for( int y=0; y<size; y++ ) for( int x=0; x<size; x++ ) _result->c(x,y) *= Blackman(x, size) * Blackman(y, size); break; case 4: // Border only int border = size / 32; for( int y=0; y<border; y++ ) for( int x=0; x<size; x++ ) { double factor = (0.54 - 0.46 * cos( 2.0 * PI * y / border / 2.0 )); _result->c(x,y) *= factor; _result->c(x,size-y-1) *= factor; } for( int x=0; x<border; x++ ) for( int y=0; y<size; y++ ) { double factor = (0.54 - 0.46 * cos( 2.0 * PI * x / border / 2.0 )); _result->c(x,y) *= factor; _result->c(size-x-1,y) *= factor; } break; } _result->FFT(); return true; }
bool IPLLocalThreshold::processInputData(IPLImage* image , int, bool) { // delete previous result delete _result; _result = NULL; int width = image->width(); int height = image->height(); if(image->type() == IPLImage::IMAGE_GRAYSCALE) _result = new IPLImage(IPLImage::IMAGE_BW, width, height); else _result = new IPLImage(image->type(), width, height); // get properties int window = getProcessPropertyInt("window"); float aboveMean = getProcessPropertyDouble("aboveMean"); int progress = 0; int maxProgress = image->height() * image->getNumberOfPlanes(); int nrOfPlanes = image->getNumberOfPlanes(); #pragma omp parallel for for( int planeNr=0; planeNr < nrOfPlanes; planeNr++ ) { IPLImagePlane* plane = image->plane( planeNr ); IPLImagePlane* newplane = _result->plane( planeNr ); int w2 = window/2; double area = (double)window*(double)window; for(int y=w2; y < height-w2; y++) { // progress notifyProgressEventHandler(100*progress++/maxProgress); for(int x=w2; x < width-w2; x++) { double localMean = 0.0; for( int kx=-w2; kx<=w2; kx++ ) { for( int ky=-w2; ky<=w2; ky++ ) { localMean += (double)plane->p(x+kx,y+ky); } } localMean /= area; double deviation = 0.0; for( int kx=-w2; kx<=w2; kx++ ) { for( int ky=-w2; ky<=w2; ky++ ) { double diff = (double)plane->p(x+kx, y+ky) - localMean; deviation += diff * diff; } } deviation = sqrt( deviation / area ); double T = (localMean + aboveMean*deviation); newplane->p(x,y) = (plane->p(x,y) >= T) ? 1.0 : 0.0; } } } return true; }
bool IPLConvolutionFilter::processInputData(IPLImage* image , int, bool useOpenCV) { // delete previous result delete _result; _result = NULL; int width = image->width(); int height = image->height(); // get properties _kernel = getProcessPropertyVectorInt("kernel"); _divisor = getProcessPropertyInt("divisor"); _offset = getProcessPropertyDouble("offset"); _normalize = getProcessPropertyBool("normalize"); _borders = getProcessPropertyInt("borders"); if(_normalize) { int sum = 0; for(size_t i=0; i<_kernel.size(); i++) { sum += _kernel[i]; } _divisor = (sum != 0 ? sum : 1); } if (_divisor == 0) { addError("Invalid divisor: 0"); return false; } float divFactor = 1.0f/_divisor; int kernelWidth = (int)sqrt((float)_kernel.size()); int kernelOffset = kernelWidth / 2; int progress = 0; int maxProgress = image->height() * image->getNumberOfPlanes(); if (!useOpenCV) { _result = new IPLImage( image->type(), width, height ); #pragma omp parallel for default(shared) for( int planeNr=0; planeNr < image->getNumberOfPlanes(); planeNr++ ) { IPLImagePlane* plane = image->plane( planeNr ); IPLImagePlane* newplane = _result->plane( planeNr ); for(int y=0; y<plane->height(); y++) { // progress notifyProgressEventHandler(100*progress++/maxProgress); for(int x=0; x<plane->width(); x++) { float sum = 0; int i = 0; for( int ky=-kernelOffset; ky<=kernelOffset; ky++ ) { for( int kx=-kernelOffset; kx<=kernelOffset; kx++ ) { int h = _kernel[i++]; if( h ) { if(_borders == 0) { // Crop borders sum += plane->cp(x+kx, y+ky) * h; } else if(_borders == 1) { // Extend borders sum += plane->bp(x+kx, y+ky) * h; } else { // Wrap borders sum += plane->wp(x+kx, y+ky) * h; } } } } sum = sum * divFactor + _offset; sum = (sum>1.0) ? 1.0 : (sum<0) ? 0.0 : sum; // clamp to 0.0 - 1.0 newplane->p(x,y) = sum; } } } } else { notifyProgressEventHandler(-1); cv::Mat src = image->toCvMat(); cv::Mat dst; cv::Mat kernel(kernelWidth, kernelWidth, CV_32FC1 ); int i = 0; for( int y=0; y < kernelWidth; y++ ) for( int x=0; x < kernelWidth; x++ ) kernel.at<float>(cv::Point(x,y)) = _kernel[i++]; kernel *= divFactor; static const int BORDER_TYPES[3] = { cv::BORDER_CONSTANT, cv::BORDER_REPLICATE, cv::BORDER_WRAP }; cv::filter2D(src, dst, -1, kernel, cv::Point(-1,-1), _offset, BORDER_TYPES[_borders]); _result = new IPLImage(dst); } return true; }
bool IPLMergePlanes::processInputData(IPLImage* image , int imageIndex, bool) { // save the inputs if(imageIndex == 0) { delete _inputA; _inputA = new IPLImage(*image); } if(imageIndex == 1) { delete _inputB; _inputB = new IPLImage(*image); } if(imageIndex == 2) { delete _inputC; _inputC = new IPLImage(*image); } // only continue if we have 2 valid inputs if(!(_inputA && _inputB && _inputC)) { return false; } // get properties int inputType = getProcessPropertyInt("input_type"); int width = std::max(std::max(_inputA->width(), _inputB->width()), _inputC->width()); int height = std::max(std::max(_inputA->height(), _inputB->height()), _inputC->height()); delete _result; _result = new IPLImage(IPLData::IMAGE_COLOR, width, height); int progress = 0; int maxProgress = image->height() * _result->getNumberOfPlanes(); // copy data for(int y=0; y<height; y++) { // progress notifyProgressEventHandler(100*progress++/maxProgress); for(int x=0; x<width; x++) { // RGB float r = _inputA->plane(0)->cp(x, y); float g = _inputB->plane(0)->cp(x, y); float b = _inputC->plane(0)->cp(x, y); // HSV if(inputType == 1) { float rgb[3]; IPLColor::hsvToRgb(r, g, b, rgb); r = rgb[0]; g = rgb[1]; b = rgb[2]; } // HSL else if(inputType == 2) { float rgb[3]; IPLColor::hslToRgb(r, g, b, rgb); r = rgb[0]; g = rgb[1]; b = rgb[2]; } _result->plane(0)->p(x, y) = r; _result->plane(1)->p(x, y) = g; _result->plane(2)->p(x, y) = b; } } return true; }
bool IPLSynthesize::processInputData(IPLImage*, int, bool) { if(isResultReady()) { //return true; } // delete previous result delete _result; _result = NULL; // get properties _type = getProcessPropertyInt("type"); _width = getProcessPropertyInt("width"); _height = getProcessPropertyInt("height"); _amplitude = getProcessPropertyDouble("amplitude"); _offset = getProcessPropertyDouble("offset"); _wavelength = getProcessPropertyInt("wavelength"); _direction = getProcessPropertyInt("plane_direction"); _decay = getProcessPropertyInt("decay"); IPLColor color = getProcessPropertyColor("flat_color"); if( _type == 0 ) _result = new IPLImage( IPL_IMAGE_COLOR, _width, _height ); else _result = new IPLImage( IPL_IMAGE_GRAYSCALE, _width, _height ); double dx = (double)_width / 2.0; double dy = (double)_height / 2.0; double direction = _direction / 180.0 * PI; // deg to rad IPLImagePlane* plane = _result->plane( 0 ); int progress = 0; int maxProgress = _result->height(); switch( _type ) { case 0: // flat plane for( int y=0; y<_height; y++ ) { notifyProgressEventHandler(100*progress++/maxProgress); for( int x=0; x<_width; x++ ) { _result->plane(0)->p(x,y) = color.red(); _result->plane(1)->p(x,y) = color.green(); _result->plane(2)->p(x,y) = color.blue(); } } break; case 1: // plane wave for( int y=0; y<_height; y++ ) { notifyProgressEventHandler(100*progress++/maxProgress); for( int x=0; x<_width; x++ ) { double dist = (x)*cos( direction ) + (_height-y)*sin( direction ); double fade = (_decay!=0) ? exp( -dist/_decay ) : 1.0; double value = _amplitude * cos(dist/_wavelength * PI * 2.0) * fade + _offset; plane->p(x,y) = ( (value<0.0)? 0.0 : (value>1.0)? 1.0 : value ); } } break; case 2:// center wave for( int y=0; y<_height; y++ ) { notifyProgressEventHandler(100*progress++/maxProgress); for( int x=0; x<_width; x++ ) { double dist = sqrt( (x-dx)*(x-dx) + (y-dy)*(y-dy) ); double fade = (_decay!=0) ? exp( -dist/_decay ) : 1.0; double value = _amplitude * cos( dist/_wavelength * PI * 2.0 ) * fade + _offset; plane->p(x,y) = ( (value<0.0)? 0.0 : (value>1.0)? 1.0 : value ); } } break; } return true; }
bool IPLMorphologyBinary::processInputData(IPLImage* image, int, bool useOpenCV) { // delete previous result delete _result; _result = NULL; int width = image->width(); int height = image->height(); // get properties _kernel = getProcessPropertyVectorInt("kernel"); _iterations = getProcessPropertyInt("iterations"); _operation = getProcessPropertyInt("operation"); if (std::accumulate(_kernel.begin(),_kernel.end(),0) == 0) { //Add an empty image - The image viewer currently may trigger //a segfault if we return NULL. _result = new IPLImage( IPLImage::IMAGE_BW, width, height); addError("Empty kernel."); return false; } // TODO: implement manhattan distance threshold instead of stupid iterations... // TODO: implement border interpolation properties enum Operation { DILATE = 0, ERODE, OPEN, CLOSE }; if (!useOpenCV) { _result = new IPLImage( IPLImage::IMAGE_BW, width, height); //std::vector<bool> packs its elements bitwise into a vector of //bytes. The kernel therefore uses much less cpu cache this way. std::vector<bool> kernel; kernel.reserve(_kernel.size()); for (auto &i: _kernel) kernel.push_back(i > 0); std::atomic<int> progress(0); int totalLines = image->height()*_iterations; auto updateProgress = [&]() { notifyProgressEventHandler(100*((float)++progress)/totalLines); }; switch(_operation) { case DILATE: dilate(*image->plane(0),*_result->plane(0),_iterations,kernel,updateProgress); break; case ERODE: erode (*image->plane(0),*_result->plane(0),_iterations,kernel,updateProgress); break; case OPEN: totalLines *= 2; open (*image->plane(0),*_result->plane(0),_iterations,kernel,updateProgress); break; case CLOSE: totalLines *= 2; close (*image->plane(0),*_result->plane(0),_iterations,kernel,updateProgress); break; } } else { notifyProgressEventHandler(-1); int kernelSize = (int)sqrt((float)_kernel.size()); cv::Mat src = image->toCvMat(); cv::Mat dst; cv::Mat kernel(kernelSize,kernelSize,CV_8UC1); int i = 0; for (auto pixel: _kernel) kernel.at<unsigned char>(i++) = pixel; static const int OPERATIONS[4] = { cv::MORPH_DILATE, cv::MORPH_ERODE, cv::MORPH_OPEN, cv::MORPH_CLOSE }; cv::morphologyEx(src,dst,OPERATIONS[_operation],kernel,cv::Point(-1,-1),_iterations); _result = new IPLImage(dst); } return true; }
bool IPLMedian::processInputData(IPLImage* image , int, bool useOpenCV) { // delete previous result delete _result; _result = NULL; int width = image->width(); int height = image->height(); // get properties int window = getProcessPropertyInt("window"); int progress = 0; int maxProgress = image->height() * image->getNumberOfPlanes(); int nrOfPlanes = image->getNumberOfPlanes(); int w2 = window/2; int area = window*window; if (!useOpenCV) { _result = new IPLImage( image->type(), width, height ); #pragma omp parallel for for( int planeNr=0; planeNr < nrOfPlanes; planeNr++ ) { IPLImagePlane* plane = image->plane( planeNr ); IPLImagePlane* newplane = _result->plane( planeNr ); ipl_basetype* list = new ipl_basetype[area]; for(int y=0; y<height; y++) { // progress notifyProgressEventHandler(100*progress++/maxProgress); for(int x=0; x<width; x++) { int i =0; for( int ky=-w2; ky<=w2; ky++ ) { for( int kx=-w2; kx<=w2; kx++ ) { list[i++] = plane->bp(x+kx, y+ky); } } // insert sort list for( int k=area; k>=0; k--) { int j = k+1; ipl_basetype temp = list[k]; while( j < area && temp > list[j] ) { list[j-1] = list[j]; j++; } list[j-1] = temp; } newplane->p(x,y) = list[area/2]; } } } } else { notifyProgressEventHandler(-1); auto src = image->toCvMat(); cv::Mat dst; cv::medianBlur(src,dst,window); _result = new IPLImage(dst); } return true; }
bool IPLGradientOperator::cubicSpline(IPLImage* image) { static float k1f[4][4] = {{-0.5,1.5,-1.5,0.5},{1.0,-2.5,2.0,-0.5},{-0.5,0,0.5,0},{0,1.0,0,0}}; static cv::Mat k1(4,4,CV_32FC1,k1f); static float k2f[4][4] = {{-0.5,1.0,-0.5,0},{1.5,-2.5,0,1},{-1.5,2.0,0.5,0},{0.5,-0.5,0,0}}; static cv::Mat k2(4,4,CV_32FC1,k2f); int width = image->width(); int height = image->height(); int progress = 0; int maxProgress = height*width; notifyProgressEventHandler(-1); cv::Mat input = image->toCvMat(); cv::Mat coeffFull = cv::Mat::zeros(height,width,CV_32FC1); cv::Mat coeff = cv::Mat::zeros(height,width,CV_32FC1); for (int i=0;i<width;i++) for (int j=0;j<height;j++) coeffFull.at<cv::Vec<float,1>>(i,j)[0] = static_cast<float>(input.at<cv::Vec<unsigned char,4>>(i,j).val[0]) * FACTOR_TO_FLOAT ; float dx,dy,x3,x2,y3,y2,xf,yf; for (int x=1; x < width - 2; x++){ for (int y = 1; y < height - 2; y++){ // progress notifyProgressEventHandler(100*progress++/maxProgress); coeffFull(cv::Range(y-1,y+3),cv::Range(x-1,x+3)).copyTo(coeff); //std::cout << coeff << std::endl; coeff = k1*coeff; coeff = coeff*k2; xf = static_cast<float>(x)/static_cast<float>(width); x2 = xf*xf; x3 = x2*xf; yf = static_cast<float>(y)/static_cast<float>(height); y2 = yf*yf; y3 = y2*yf; float dyMatf[4][4] = {{3.f*y2*x3,3.f*y2*x2,3.f*y2*xf,3.f*y2}, {2.f*yf*x3,2.f*yf*x2,2.f*yf*xf,2.f*yf}, {x3,x2,xf,1.f}, {0.f,0.f,0.f,0.f}}; float dxMatf[4][4] = {{3.f*x2*y3,2.f*xf*y3,y3,0.f}, {3.f*x2*y2,2.f*xf*y2,y2,0.f}, {3.f*x2*yf,2.f*xf*yf,yf,0.f}, {3.f*x2,2.f*xf,1.f,0.f}}; cv::Mat dxMat(4,4,CV_32FC1,dxMatf); cv::Mat dyMat(4,4,CV_32FC1,dyMatf); dx = coeff.dot(dxMat); dy = coeff.dot(dyMat); double phase = (dx!=0.0 || dy!=0.0 )? atan2( -dy, dx ) : 0.0; while( phase > 2.0 * PI ) phase -= 2.0 * PI; while( phase < 0.0 ) phase += 2.0 * PI; // phase 0.0-1.0 phase /= 2 * PI; _result->phase(x,y) = phase; _result->magnitude(x,y) = sqrt(dx*dx + dy*dy); } } return true; }
bool IPLBinarizeUnimodal::processInputData(IPLImage* image , int, bool) { // delete previous result delete _result; _result = NULL; int width = image->width(); int height = image->height(); if( image->type() == IPL_IMAGE_GRAYSCALE ) _result = new IPLImage( IPL_IMAGE_BW, width, height ); else _result = new IPLImage( image->type(), width, height ); int progress = 0; int maxProgress = image->height() * image->getNumberOfPlanes(); int nrOfPlanes = image->getNumberOfPlanes(); #pragma omp parallel for for( int planeNr=0; planeNr < nrOfPlanes; planeNr++ ) { IPLImagePlane* plane = image->plane( planeNr ); IPLImagePlane* newplane = _result->plane( planeNr ); int p[256] = { 0 }; for( int y = 0; y < height; ++y ) { for( int x = 0; x < width; ++x ) { int index = plane->p(x,y) * 255; p[index]++; } } // determine maxEntry int maxBin = 0; int maxFrequency = 0; for( int k=1; k<255; ++k ) { if( p[k] > maxFrequency ) { maxFrequency = p[k]; maxBin = k; } } // determine zeroEntry int zeroBin = 0; int x0, x1; if( maxBin >= 128 ) { zeroBin = 0; while( p[zeroBin]==0 ) ++zeroBin; x0 = zeroBin; x1 = maxBin; } else { zeroBin = 255; while( p[zeroBin]==0 ) --zeroBin; x0 = maxBin; x1 = zeroBin; } int y0 = p[x0]; int y1 = p[x1]; double a = y0 - y1; double b = x1 - x0; double c = x0*y1 - x1*y0; double d = sqrt( a*a + b*b ); int T = 0; if( d != 0.0 ) { double maxDist = 0.0; for( int k=x0; k<=x1; ++k ) { double distance = std::abs( ( a*k + b*p[k] + c ) / d ); if( distance > maxDist ) { maxDist = distance; T = k; } } } ipl_basetype threshold = T * FACTOR_TO_FLOAT; std::stringstream s; s << "Automatic Threshold: "; s << threshold; addInformation(s.str()); for(int y = 0; y < height; y++) { // progress notifyProgressEventHandler(100*progress++/maxProgress); for(int x = 0; x < width; x++) { newplane->p(x,y)= (plane->p(x,y) > threshold)? 1.0 : 0.0; } } } return true; }
bool IPLMorphologicalEdge::processInputData(IPLImage* image , int, bool) { // delete previous result delete _result; _result = NULL; int width = image->width(); int height = image->height(); _result = new IPLImage( image->type(), width, height ); // get properties int window = getProcessPropertyInt("window"); int progress = 0; int maxProgress = image->height() * image->getNumberOfPlanes() * 2; int nrOfPlanes = image->getNumberOfPlanes(); int w2 = window/2; int area = window*window; #pragma omp parallel for for( int planeNr=0; planeNr < nrOfPlanes; planeNr++ ) { IPLImagePlane* plane = image->plane( planeNr ); IPLImagePlane* newplane = _result->plane( planeNr ); IPLImagePlane* average = new IPLImagePlane(width, height); for(int x=w2; x<width-w2; x++) { // progress notifyProgressEventHandler(100*progress++/maxProgress); for(int y=w2; y<height-w2; y++) { ipl_basetype sum = 0; for( int kx=-w2; kx<=w2; kx++ ) { for( int ky=-w2; ky<=w2; ky++ ) { if( kx || ky ) sum += plane->p(x+kx, y+ky); } } average->p(x,y) = sum; } } for(int x=w2; x<width-w2; x++) { // progress notifyProgressEventHandler(100*progress++/maxProgress); for(int y=w2; y<height-w2; y++) { float minc = (area-1); float maxc = 0; for( int kx=-w2; kx<=w2; kx++ ) { for( int ky=-w2; ky<=w2; ky++ ) { ipl_basetype img = average->bp(x+kx, y+ky); if( img > maxc) maxc = img; if( img < minc) minc = img; } } ipl_basetype img = average->p(x,y); ipl_basetype d1 = img - minc; ipl_basetype d2 = maxc - img; ipl_basetype min = (d1 < d2)? d1 : d2; min = (min<1.0)? min : 1.0; min = (min>0.0)? min : 0.0; newplane->p(x,y) = min; } } delete average; } return true; }
bool IPLCanny::processInputData(IPLImage* image , int, bool useOpenCV) { // delete previous result delete _result; _result = NULL; delete _binaryImage; _binaryImage = NULL; int width = image->width(); int height = image->height(); _result = new IPLImage( image->type(), width, height ); _binaryImage = new IPLImage( IPLData::IMAGE_BW, width, height ); // get properties int window = getProcessPropertyInt("window"); double sigma = getProcessPropertyDouble("sigma"); double lowThreshold = getProcessPropertyDouble("lowThreshold"); double highThreshold = getProcessPropertyDouble("highThreshold"); std::stringstream s; s << "Window: "; s << window; addInformation(s.str()); //! @todo currently only the opencv implementation works if(useOpenCV || true) { notifyProgressEventHandler(-1); cv::Mat input; cv::Mat output; cvtColor(image->toCvMat(), input, CV_BGR2GRAY); cv::Canny(input, output, lowThreshold*255, highThreshold*255, window); delete _result; _result = new IPLImage(output); return true; } return false; // Create a Gaussian 1D filter int N = ceil( sigma * sqrt( 2.0*log( 1.0/0.015 ) ) + 1.0 ); double ssq = sigma*sigma; double* gau = new double [window]; double* dgau = new double [window]; for( int k = -N; k <= N; ++k ) { gau[k+N] = gauss ( (double)k, ssq ); dgau[k+N] = dGauss ( (double)k, 0, ssq ); } // Create a directional derivative of 2D Gaussian (along X-axis) // Since the result is symmetric along X, we can get the derivative along // Y-axis simply by transposing the result for X direction. // DoubleImage* dgau = new DoubleImage( window, window ); // for( int y = -N; y <= N; ++y ) // for( int x = -N; x <= N; ++x ) // dgau->f(x+N, y+N) = dGauss( x, y, ssq ); int progress = 0; int maxProgress = width * image->getNumberOfPlanes(); int nrOfPlanes = image->getNumberOfPlanes(); //#pragma omp parallel for for( int planeNr=0; planeNr < nrOfPlanes; planeNr++ ) { IPLImagePlane* plane = image->plane( planeNr ); IPLImagePlane* newplane = _result->plane( planeNr ); // ******** Gaussian filtering of input image IPLImagePlane* gI = new IPLImagePlane( width, height ); // horizontal run (normalizing original image) IPLImagePlane* tmpI = new IPLImagePlane( width, height ); for(int x=0; x<width; x++) { // progress notifyProgressEventHandler(100*progress++/maxProgress); for(int y=0; y<height; y++) { double sum = 0; int i = 0; for( int kx=-N; kx<=N; kx++ ) { double img = (double) plane->bp(x+kx, y); sum += (img * gau[i++]); } tmpI->p(x,y) = (double) (sum); } } // vertiacl run for(int x=0; x<width; x++) { for(int y=0; y<height; y++) { double sum = 0; int i = 0; for( int ky=-N; ky<=N; ky++ ) { double img = tmpI->bp(x, y+ky); sum += (img * gau[i++]); } gI->p(x,y) = sum; } } //delete tmpI; // ******** Apply directional derivatives ... // ... in x-direction IPLImagePlane* dx = new IPLImagePlane( width, height ); for(int x=0; x<width; x++) { for(int y=0; y<height; y++) { dx->p(x,y) = 0.0; for( int k=1; k<N; k++ ) { dx->p(x,y) += ( gI->bp(x-k,y) - gI->bp(x+k,y) ) * dgau[k]; } } } // double maxVal = 0.0; // for(int x=0; x<width; x++) // for(int y=0; y<height; y++) // if( dx->f(x,y) > maxVal ) maxVal = dx->f(x,y); // ... in y-direction IPLImagePlane* dy = new IPLImagePlane( width, height ); for(int x=0; x<width; x++) { for(int y=0; y<height; y++) { dy->p(x,y) = 0.0; for( int k=1; k<N; k++ ) { dy->p(x,y) += ( gI->bp(x,y-k) - gI->bp(x,y+k) ) * dgau[k]; } } } // ******** Compute magnitude and binarization thresholds IPLImagePlane* mag = new IPLImagePlane( width, height ); double magMax = 0.0; double magMin = 999999999.0; for(int x=0; x<width; x++) { for(int y=0; y<height; y++) { double val = sqrt( dx->p(x,y)*dx->p(x,y) + dy->p(x,y)*dy->p(x,y) ); mag->p(x,y) = val; if( val > magMax ) magMax = val; if( val < magMin ) magMin = val; } } //// ******** Non-maxima suppression - edge pixels should be a local maximum _orientedImage = new IPLOrientedImage( width, height ); for(int x=0; x<width; x++) { for(int y=0; y<height; y++) { double ix = dx->p(x,y); double iy = dy->p(x,y); double g = mag->p(x,y); // determine 4-neighbor direction of gradient int dir4 = 0; if( (iy<=0.0 && ix>-iy) || (iy>=0.0 && ix<-iy) ) dir4 = 1; else if( (ix>0.0 && -iy>=ix) || (ix<0.0 && -iy<=ix) ) dir4 = 2; else if( (ix<=0.0 && ix>iy) || (ix>=0.0 && ix<iy) ) dir4 = 3; else if( (iy<0.0 && ix<=iy) || (iy>0.0 && ix>=iy) ) dir4 = 4; else continue; double gradmag1, gradmag2, d; switch(dir4) { case 1: d = std::fabs(iy/ix); gradmag1 = mag->bp(x+1,y)*(1-d) + mag->bp(x+1,y-1)*d; gradmag2 = mag->bp(x-1,y)*(1-d) + mag->bp(x-1,y+1)*d; break; case 2: d = std::fabs(ix/iy); gradmag1 = mag->bp(x,y-1)*(1-d) + mag->bp(x+1,y-1)*d; gradmag2 = mag->bp(x,y+1)*(1-d) + mag->bp(x-1,y+1)*d; break; case 3: d = std::fabs(ix/iy); gradmag1 = mag->bp(x,y-1)*(1-d) + mag->bp(x-1,y-1)*d; gradmag2 = mag->bp(x,y+1)*(1-d) + mag->bp(x+1,y+1)*d; break; case 4: d = std::fabs(iy/ix); gradmag1 = mag->bp(x-1,y)*(1-d) + mag->bp(x-1,y-1)*d; gradmag2 = mag->bp(x+1,y)*(1-d) + mag->bp(x+1,y+1)*d; break; } if( g > gradmag1 && g > gradmag2 ) { _orientedImage->magnitude(x,y) = g; _orientedImage->phase(x,y) = atan2(iy,ix); } } } for(int x=0; x<width; x++) { for(int y=0; y<height; y++) { _orientedImage->magnitude(x,y) /= magMax; double val = _orientedImage->magnitude(x,y)*255.0; // double val = mag->f(x,y)/magMax*255.0; if (val > 255.0 ) val = 255.0; if (val < 0.0 ) val = 0.0; newplane->p(x,y) = (unsigned char ) val; } } // ******** Binarize with hysteresis threshold double hist[ 256 ]; for( int i=0; i<256; ++i ) hist[i] = 0; int pixCount = 0; for(int x=0; x<width; x++) { for(int y=0; y<height; y++) { if( _orientedImage->magnitude(x,y) > 0.0 ) { int index = floor( _orientedImage->magnitude(x,y)*256.0+0.5 ); ++hist[ index ]; ++pixCount; } } } double PercentOfPixelsNotEdges = 0.7*pixCount; double highThresh = 0.0; double cumsum = 0.0; for( int i=0; i<256; ++i ) { cumsum += hist[i]; if( cumsum > PercentOfPixelsNotEdges ) { highThresh = (double)i / 256.0; break; } } double lowThresh = 0.4 * highThresh; IPLImagePlane* binPlane = _binaryImage->plane( 0 ); for(int x=0; x<width; x++) { for(int y=0; y<height; y++) { if(_orientedImage->magnitude(x,y) >= highThresh) trace(x, y, lowThresh, _orientedImage, binPlane); } } //delete dx; //delete dy; //delete gI; thinning(_orientedImage, binPlane, newplane ); } //delete [] gau; //delete [] dgau; return true; }