Saturday, May 13, 2017

OpenCV - How to apply adaptive threshold to an image on iOS

Leave a Comment

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; } 

its working for me check the output for your document

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:

If You Enjoyed This, Take 5 Seconds To Share It

0 comments:

Post a Comment