Hi,
I am facing a strange issue regarding image drawing with objective C in NSImageView controls. The code below is the actual snippet that reproduces the issue (just define a true path for the image) :
I create 2 mat objects, one by reading an image file, the second one is of the same size, but black.
A timer is supposed to update both images in their respective NSImageView control at the same time.
Drawing is done by converting the file image to RGB, as opencv images are stored in a BGR way.
Hence, the program is supposed to display the file image in the first control, and the black image in the second one, each time the timer is triggered.
For testing purpose, I defined 2 options :
SYNCHRONIZE : both drawings are done at the same timer trigger. If not defined, refresh one control after the other, at 2 successive timer triggers.
USE_CONVERT : converts the original image from RGB to BGR and draws the converted mat image. If not defined, uses the original mat image for drawing.
My goal is to have USE_CONVERT and SYNCHRONIZE activated. The issue is that, in that case, the file image is displayed in both controls, where I would like to have the file image in one control and the black one in the other one.
Moreover, if USE_CONVERT is defined but SYNCHRONIZE is not defined, it works correctly !
As soon as I do not use cvtColor (USE_CONVERT is not defined) I actually get the black frame in second control and the file image in the first one, but of course file image is displayed with wrong colors.
It looks like some object is still alive (and used) when called successively, while released if called at different timer calls. Can someone explain to me what is wrong with this implementation ?
Thanks in advance.
#import "AppDelegate.h" #import "opencv2/opencv.hpp" using namespace cv; #define USE_CONVERT #define SYNCHRONIZE @implementation AppDelegate NSTimer *timer = nil; Mat matFrame1; Mat matFrame2; bool first = false; - (void)applicationDidFinishLaunching:(NSNotification *)aNotification { // Insert code here to initialize your application matFrame1 = imread("/Users/..../image.bmp"); matFrame2 = Mat::zeros(matFrame1.rows, matFrame1.cols, CV_8UC3); timer = [NSTimer scheduledTimerWithTimeInterval:.1 target:self selector:@selector(timerGUI) userInfo:nil repeats:YES]; } -(void)timerGUI { NSLog(@"TimerGUI"); #ifndef SYNCHRONIZE if (first) #endif [self drawImage : matFrame2 : self.imageView2]; #ifndef SYNCHRONIZE else #endif [self drawImage : matFrame1 : self.imageView1]; first = first ? false : true; } - (void)drawImage : (Mat)matImage : (NSImageView *)View{ NSImage* img = nil; NSBitmapImageRep* bitmapRep = nil; #ifdef USE_CONVERT Mat dispImage; cvtColor(matImage, dispImage, CV_BGR2RGB); bitmapRep = [[NSBitmapImageRep alloc] initWithBitmapDataPlanes:&dispImage.data pixelsWide:dispImage.cols pixelsHigh:dispImage.rows bitsPerSample:8 samplesPerPixel:3 hasAlpha:NO isPlanar:NO colorSpaceName:NSCalibratedRGBColorSpace bytesPerRow:dispImage.step bitsPerPixel:0]; img = [[NSImage alloc] initWithSize:NSMakeSize(dispImage.cols, dispImage.rows)]; #else bitmapRep = [[NSBitmapImageRep alloc] initWithBitmapDataPlanes:&matImage.data pixelsWide:matImage.cols pixelsHigh:matImage.rows bitsPerSample:8 samplesPerPixel:3 hasAlpha:NO isPlanar:NO colorSpaceName:NSCalibratedRGBColorSpace bytesPerRow:matImage.step bitsPerPixel:0]; img = [[NSImage alloc] initWithSize:NSMakeSize(matImage.cols, matImage.rows)]; #endif [img addRepresentation:bitmapRep]; [View setImage:img]; #ifdef USE_CONVERT dispImage.release(); #endif bitmapRep = nil; img = nil; } @end
#import <cocoa cocoa.h=""> @interface AppDelegate : NSObject <nsapplicationdelegate> @property (assign) IBOutlet NSWindow *window; @property (weak) IBOutlet NSImageView *imageView1; @property (weak) IBOutlet NSImageView *imageView2; @end