CV::MAT preview the image in debug mode - c++

if the image is UIImage we can view the image in the debug mode in xcode, but I can't for cv::mat images and it's normal, so is there anyway or any add-on tool we can add to xcode to show (or view) the image in the debug mode for cv::mat image?

If you can use CLion instead Xcode you can utilize the OpenCV Image Viewer plugin, which displays matrices while debugging just on click.
https://plugins.jetbrains.com/plugin/14371-opencv-image-viewer
Disclaimer: I'm an author of this plugin

You should create an ios project which installs opencv2.framework in it, and drag your cpp code to that project, make an new entry to run then you should be able to use the above convert code to view a mat as UIImage...

I don't know if I understood your question, but if you wanna simply display a cv::Mat preview, you can convert the cv::Mat to UIImage. I can show you how to do that in Objective-C:
-(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);
// Creating CGImage from cv::Mat
CGImageRef imageRef = CGImageCreate(cvMat.cols, //width
cvMat.rows, //height
8, //bits per component
8 * cvMat.elemSize(), //bits per pixel
cvMat.step[0], //bytesPerRow
colorSpace, //colorspace
kCGImageAlphaNone|kCGBitmapByteOrderDefault,// bitmap info
provider, //CGDataProviderRef
NULL, //decode
false, //should interpolate
kCGRenderingIntentDefault //intent
);
// Getting UIImage from CGImage
UIImage *finalImage = [UIImage imageWithCGImage:imageRef];
CGImageRelease(imageRef);
CGDataProviderRelease(provider);
CGColorSpaceRelease(colorSpace);
return finalImage;
}
If this is what you asked, there are a lot of similar question on StackOveflow:
how to convert from cvMat to UIImage in objective-c?
how to convert from cvMat to UIImage in objective-c?

Related

Store cv::Mat in Swift variable

I have a c++ opencv function that gets the gray scale of an image and stores it into an array.
+(cv::Mat) makeGray:(UIImage *) image {
// Transform UIImage to cv::Mat
cv::Mat imageMat;
UIImageToMat(image, imageMat);
//Transform image to grayscale
cv::Mat grayMat;
cv::cvtColor(imageMat, grayMat, CV_BGR2GRAY);
return grayMat;
}
Whenever I try storing this in a variable using swift
swift function:
#IBAction func convertImage(_ sender: UIButton) {
let grayMat = OpenCVWrapper.makeGray(photoImageView.image)
}
The entire program just freezes without throwing out an error.
The swift function works great when I return an UIImage:
+(UIImage *) makeGray:(UIImage *) image {
// Transform UIImage to cv::Mat
cv::Mat imageMat;
UIImageToMat(image, imageMat);
//Transform image to grayscale
cv::Mat grayMat;
cv::cvtColor(imageMat, grayMat, CV_BGR2GRAY);
return MatToUIImage(grayMat);
}
But I'm looking to return a 3darray and not an Image.

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

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.
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
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:

function non recognized in objective-C

I'm new to IOS developing but this problem i'm facing does not seem logical to me. I'm declaring a function in both ViewController.h and ViewController.mm (changed to.mm because i'm using C++) but when i call it in ViewController.mm i get use of undeclared identifier error.
Here's the declaration in the header file:
#import <UIKit/UIKit.h>
#import <opencv2/highgui/cap_ios.h>
using namespace cv;
#interface ViewController : UIViewController<CvVideoCameraDelegate>
{
IBOutlet UIImageView* imageview;
CvVideoCamera* videoCamera;
IBOutlet UILabel *label;
}
- (UIImage *) CVMatToImage:(cv::Mat) matrice;
#property (nonatomic, retain) CvVideoCamera* videoCamera;
-(IBAction)cameraStart:(id)sender;
-(IBAction)cameraStop:(id)sender;
#end
and the definition in the .mm file:
- (UIImage *) CVMatToImage:(cv::Mat) matrice
{
NSData *data = [NSData dataWithBytes:matrice.data length:matrice.elemSize()*matrice.total()];
CGColorSpaceRef colorSpace;
CGBitmapInfo bitmapInfo;
if (matrice.elemSize() == 1) {
colorSpace = CGColorSpaceCreateDeviceGray();
bitmapInfo = kCGImageAlphaNone | kCGBitmapByteOrderDefault;
} else {
colorSpace = CGColorSpaceCreateDeviceRGB();
bitmapInfo = kCGBitmapByteOrder32Little | (
matrice.elemSize() == 3? kCGImageAlphaNone : kCGImageAlphaNoneSkipFirst
);
}
CGDataProviderRef provider = CGDataProviderCreateWithCFData((__bridge CFDataRef)data);
// Creating CGImage from cv::Mat
CGImageRef imageRef = CGImageCreate(
matrice.cols, //width
matrice.rows, //height
8, //bits per component
8 * matrice.elemSize(), //bits per pixel
matrice.step[0], //bytesPerRow
colorSpace, //colorspace
bitmapInfo, // bitmap info
provider, //CGDataProviderRef
NULL, //decode
false, //should interpolate
kCGRenderingIntentDefault //intent
);
// Getting UIImage from CGImage
UIImage *finalImage = [UIImage imageWithCGImage:imageRef];
CGImageRelease(imageRef);
CGDataProviderRelease(provider);
CGColorSpaceRelease(colorSpace);
return finalImage;
}
But when i call it inside an IBAction i get an error
-(IBAction)cameraStop:(id)sender
{
[self.videoCamera stop];
//////////////////////
// Don't forget to process image here
//////////////////////
UIImage *finalImageToOCR = CVMatToImage(cvMatrice);
[imageview setImage:finalImageToOCR];
G8Tesseract *tesseract = [[G8Tesseract alloc] initWithLanguage:#"fra"];
[tesseract setImage:finalImageToOCR];
[tesseract recognize];
NSLog(#"%#", [tesseract recognizedText]);
label.text = [NSString stringWithFormat:[tesseract recognizedText]];
}
You have defined an instance method and not a function. Like the other method calls in your code you need to use a method call along the lines of:
UIImage *finalImageToOCR = [<object instance> CVMatToImage:cvMatrice];
Alternatively if you want a function you would declare is as:
UIImage *CVMatToImage(cv::Mat matrice) { ... }
in which case the function cannot access any instance variables.
HTH

Conversion of Mat to UIImage from CvVideoCamera

I am storing frames in real time from a CvVideoCamera using the - (void)processImage:(Mat&)image delegate method.
After storing the images I average them all into one image to replicate a long exposure shot using this code:
Mat merge(Vector<Mat> frames, double alpha)
{
Mat firstFrame = frames.front();
Mat exposed = firstFrame * alpha;
for (int i = 1; i < frames.size(); i++) {
Mat frame = frames[i];
exposed += frame * alpha;
}
return exposed;
}
After getting the averaged image back I convert it back to a UIImage, but the image I get back is in a strange color space, does anyone know how I can fix this?
Conversion code:
+ (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, cvMat.rows, 8, 8 * cvMat.elemSize(), cvMat.step[0], colorSpace, kCGImageAlphaNone|kCGBitmapByteOrderDefault, provider, NULL, false, kCGRenderingIntentDefault );
UIImage *finalImage = [UIImage imageWithCGImage:imageRef];
CGImageRelease( imageRef );
CGDataProviderRelease( provider );
CGColorSpaceRelease( colorSpace );
return finalImage;
}
Here is an example(note: the plane in the middle is because I am recording off a computer monitor)

Converting to UIImage from cvMat alters image

Whenever I try to convert my binary image back to a UIImage it changes the areas that should be white to a dark blue. I have seen that other people have been having similar issues, but have found no solution.
Here is the code I am using to convert to a UIImage
- (UIImage *)UIImageFromMat:(cv::Mat)image
{
NSData *data = [NSData dataWithBytes:image.data length:image.elemSize()*image.total()];
CGColorSpaceRef colorSpace;
if (image.elemSize() == 1) {
colorSpace = CGColorSpaceCreateDeviceGray();
} else {
colorSpace = CGColorSpaceCreateDeviceRGB();
}
CGDataProviderRef provider = CGDataProviderCreateWithCFData((CFDataRef)data);//CGDataProviderCreateWithCFData((__bridge CFDataRef)data);
// Creating CGImage from cv::Mat
CGImageRef imageRef = CGImageCreate(image.cols, //width
image.rows, //height
8, //bits per component
8 * image.elemSize(), //bits per pixel
image.step.p[0], //bytesPerRow
colorSpace, //colorspace
kCGImageAlphaNone|kCGBitmapByteOrderDefault,// bitmap info
provider, //CGDataProviderRef
NULL, //decode
false, //should interpolate
kCGRenderingIntentDefault //intent
);
// Getting UIImage from CGImage
UIImage *finalImage = [UIImage imageWithCGImage:imageRef];
//[self.imgView setImage:finalImage];
CGImageRelease(imageRef);
CGDataProviderRelease(provider);
CGColorSpaceRelease(colorSpace);
return finalImage;
}
Can anyone provide some insight as to why my code for converting to a UIImage changes the image? And how to fix it?
Found that I need to apply this code before converting to a UIImage
res.convertTo(res, CV_8UC3, 255.0);
I do not know what is the reason but you can fix an image using
CGImageRef CGImageCreateWithMaskingColors (
CGImageRef image,
const CGFloat components[]
);
Description Creates a bitmap image by masking an existing bitmap
image with the provided color values. Any image sample with color
value {c[1], ... c[N]} where min[i] <= c[i] <= max[i] for 1 <= i <= N
is masked out (that is, not painted). This means that anything
underneath the unpainted samples, such as the current fill color,
shows through.
So you will need something like
UIImage *your_image; // do not forget to initialize it
const CGFloat blueMasking[6] = {0.0, 0.05, 0.0, 0.05, 0.95, 1.0};
CGImageRef image = CGImageCreateWithMaskingColors(your_image.CGImage, blueMasking);
UIImage *new_image = [UIImage imageWithCGImage:image];
https://stackoverflow.com/questions/22429538/turn-all-pixels-of-chosen-color-to-white-uiimage/22429897#22429897