Steven Bedrick

Getting an OpenCV IplImage from an NSImage

« Back to notes

There are plenty of places online to find out how to get an NSImage from an OpenCV IplImage, but, for whatever reason, I had a devil of a time figuring out how to go in the other direction. This code seems to work, and as far as I can tell doesn’t leak memory— but I could be completely wrong. If any Objective-C or OpenCV wizards happen across this code, please let me know if it’s got any glaring problems.

- (IplImage*) nsImageToIplImage:(NSImage*)img {
	
	NSBitmapImageRep *orig = [[img representations] objectAtIndex: 0];
	
	// [NSImage -representations] operates in-place, so we have to make
	// a copy or else the color-channel shift that we do later on will affect the original NSImage!
	NSBitmapImageRep *rep = [NSBitmapImageRep imageRepWithData:[orig representationUsingType:NSTIFFFileType properties:NULL]];
	
	int depth = [rep bitsPerSample];
	int channels = [rep samplesPerPixel];
	int height = [rep size].height;
	int width = [rep size].width;
	
	// note- channels had better be "3", or else the loop down below will act pretty funky...
    // NSTIFFFileType seems to always give three-channel images, so I think it's okay...
	IplImage* to_return = cvCreateImage(cvSize(width, height), depth, channels); 
	
	// found this cvSetData trick here: http://www.osxentwicklerforum.de/thread.php?postid=89767
	cvSetData(to_return, [rep bitmapData], [rep bytesPerRow]);
	
	// Reorder BGR to RGB
	// no, I don't know why it's in BGR after cvSetData
	for (int i = 0; i < to_return->imageSize; i += 3) {
		uchar tempR, tempG, tempB;
		tempR = to_return->imageData[i+2];
		tempG = to_return->imageData[i+1];
		tempB = to_return->imageData[i];
		
		to_return->imageData[i] = tempR;
		to_return->imageData[i+1] =tempG;
		to_return->imageData[i+2] = tempB;		
	}

	return to_return;
}

« Back to notes