I am trying to apply adaptive thresholding to an image of an A4 paper as shown below:
I use the code below to apply the image manipulation:
+ (UIImage *)processImageWithOpenCV:(UIImage*)inputImage { cv::Mat cvImage = [inputImage CVMat]; cv::Mat res; cv::cvtColor(cvImage, cvImage, CV_RGB2GRAY); cvImage.convertTo(cvImage,CV_32FC1,1.0/255.0); CalcBlockMeanVariance(cvImage,res); res=1.0-res; res=cvImage+res; cv::threshold(res,res, 0.85, 1, cv::THRESH_BINARY); cv::resize(res, res, cv::Size(res.cols/2,res.rows/2)); return [UIImage imageWithCVMat:cvImage]; } void CalcBlockMeanVariance(cv::Mat Img,cv::Mat Res,float blockSide=13) // blockSide - the parameter (set greater for larger font on image) { cv::Mat I; Img.convertTo(I,CV_32FC1); Res=cv::Mat::zeros(Img.rows/blockSide,Img.cols/blockSide,CV_32FC1); cv::Mat inpaintmask; cv::Mat patch; cv::Mat smallImg; cv::Scalar m,s; for(int i=0;i<Img.rows-blockSide;i+=blockSide) { for (int j=0;j<Img.cols-blockSide;j+=blockSide) { patch=I(cv::Rect(j,i,blockSide,blockSide)); cv::meanStdDev(patch,m,s); if(s[0]>0.01) // Thresholding parameter (set smaller for lower contrast image) { Res.at<float>(i/blockSide,j/blockSide)=m[0]; }else { Res.at<float>(i/blockSide,j/blockSide)=0; } } } cv::resize(I,smallImg,Res.size()); cv::threshold(Res,inpaintmask,0.02,1.0,cv::THRESH_BINARY); cv::Mat inpainted; smallImg.convertTo(smallImg,CV_8UC1,255); inpaintmask.convertTo(inpaintmask,CV_8UC1); inpaint(smallImg, inpaintmask, inpainted, 5, cv::INPAINT_TELEA); cv::resize(inpainted,Res,Img.size()); Res.convertTo(Res,CV_8UC3); }
Although the inputted image is greyscaled, it outputs an yellowish image as shown below:
My hypothesis is that whilst conversion between the cv::Mat and UIImage, something happened leading to the color image, however I can not figure out how to fix this issue.
**please ignore the status bar as these images are screenshots of the iOS app.
Update: I have tried using CV_8UC1
instead of CV_8UC3
for Res.convertTo()
and added cvtColor(Res, Res, CV_GRAY2BGR);
but am still getting very similar results.
Could it be the conversion between cv::mat and UIImage which is causing this problem??
I want my image to be like this shown below.
2 Answers
Answers 1
You can use OpenCV framework and implement below code
+(UIImage *)blackandWhite:(UIImage *)processedImage { cv::Mat original = [MMOpenCVHelper cvMatGrayFromAdjustedUIImage:processedImage]; cv::Mat new_image = cv::Mat::zeros( original.size(), original.type() ); original.convertTo(new_image, -1, 1.4, -50); original.release(); UIImage *blackWhiteImage=[MMOpenCVHelper UIImageFromCVMat:new_image]; new_image.release(); return blackWhiteImage; } + (cv::Mat)cvMatGrayFromAdjustedUIImage:(UIImage *)image { cv::Mat cvMat = [self cvMatFromAdjustedUIImage:image]; cv::Mat grayMat; if ( cvMat.channels() == 1 ) { grayMat = cvMat; } else { grayMat = cv :: Mat( cvMat.rows,cvMat.cols, CV_8UC1 ); cv::cvtColor( cvMat, grayMat, cv::COLOR_BGR2GRAY ); } return grayMat; } + (cv::Mat)cvMatFromAdjustedUIImage:(UIImage *)image { CGColorSpaceRef colorSpace = CGImageGetColorSpace(image.CGImage); CGFloat cols = image.size.width; CGFloat rows = image.size.height; cv::Mat cvMat(rows, cols, CV_8UC4); // 8 bits per component, 4 channels CGContextRef contextRef = CGBitmapContextCreate(cvMat.data, // Pointer to backing data cols, // Width of bitmap rows, // Height of bitmap 8, // Bits per component cvMat.step[0], // Bytes per row colorSpace, // Colorspace kCGImageAlphaNoneSkipLast | kCGBitmapByteOrderDefault); CGContextDrawImage(contextRef, CGRectMake(0, 0, cols, rows), image.CGImage); CGContextRelease(contextRef); return cvMat; } + (UIImage *)UIImageFromCVMat:(cv::Mat)cvMat { NSData *data = [NSData dataWithBytes:cvMat.data length:cvMat.elemSize() * cvMat.total()]; CGColorSpaceRef colorSpace; if (cvMat.elemSize() == 1) { colorSpace = CGColorSpaceCreateDeviceGray(); } else { colorSpace = CGColorSpaceCreateDeviceRGB(); } CGDataProviderRef provider = CGDataProviderCreateWithCFData((__bridge CFDataRef)data); CGImageRef imageRef = CGImageCreate(cvMat.cols, // Width cvMat.rows, // Height 8, // Bits per component 8 * cvMat.elemSize(), // Bits per pixel cvMat.step[0], // Bytes per row colorSpace, // Colorspace kCGImageAlphaNone | kCGBitmapByteOrderDefault, // Bitmap info flags provider, // CGDataProviderRef NULL, // Decode false, // Should interpolate kCGRenderingIntentDefault); // Intent UIImage *image = [[UIImage alloc] initWithCGImage:imageRef]; CGImageRelease(imageRef); CGDataProviderRelease(provider); CGColorSpaceRelease(colorSpace); return image; }
Answers 2
Try this:
+ (UIImage *)processImageWithOpenCV:(UIImage*)inputImage { cv::Mat cvImage = [inputImage CVMat]; threshold(cvImage, cvImage, 128, 255, cv::THRESH_BINARY); return [UIImage imageWithCVMat:cvImage]; }
Result image:
0 comments:
Post a Comment