{"id":37,"date":"2009-04-02T10:53:04","date_gmt":"2009-04-02T00:53:04","guid":{"rendered":"http:\/\/computer-vision-software.com\/blog\/?p=37"},"modified":"2009-11-30T12:58:43","modified_gmt":"2009-11-30T02:58:43","slug":"opencv-vs-apple-iphone","status":"publish","type":"post","link":"http:\/\/www.computer-vision-software.com\/blog\/2009\/04\/opencv-vs-apple-iphone\/","title":{"rendered":"OpenCV vs. Apple iPhone"},"content":{"rendered":"<p>This time OpenCV was ported to the Apple iPhone platform.<\/p>\n<p>First of all we need to compile OpenCV library itself so that it can be used on the iPhone. There are two ways here:<\/p>\n<p>1. Use OpenCV as a private framework.<br \/>\n2. Compile OpenCV as a static library.<\/p>\n<p>First approach looks more comfortable for using, though I was not able to make it work properly on the iPhone (it works fine on the simulator, but not on the real hardware).<\/p>\n<p>But anyway, let&#8217;s see how both approaches can be followed.<\/p>\n<p><!--more--><strong>1. Private framework<\/strong><\/p>\n<p>Instructions on how to build universal OpenCV framework for simulator and iPhone (this will support i686 and ARM) can be found <a onclick=\"javascript:pageTracker._trackPageview('\/outgoing\/zaaghad.blogspot.com\/2009\/02\/universal-i386arm-opencv-framework-for.html');\" title=\"here\"  href=\"http:\/\/zaaghad.blogspot.com\/2009\/02\/universal-i386arm-opencv-framework-for.html\" target=\"_blank\">here<\/a>.<\/p>\n<p>To add this framework to your application do following:<\/p>\n<p>1. Create new application in the Xcode.<br \/>\n2. Right-click framework group and select &#8220;Add -&gt; Existing Frameworks&#8221;<br \/>\n3. Select OpenCV.framework folder you have created.<br \/>\n4. In the Xcode menu select &#8220;Project -&gt; New Build Phase -&gt; New Copy Files Build Phase&#8221;<br \/>\n5. In the opened window select &#8220;Frameworks&#8221; as destination and close the window.<br \/>\n6. Now expand group &#8220;Targets -&gt; your_target&#8221; and drug OpenCV.framework from the Frameworks group to the &#8220;Copy Files&#8221; group under your target.<br \/>\n7. Add &#8220;#import &lt;OpenCV\/OpenCV.h&gt;&#8221; anywhere in your code (not anywhere, but&#8230; well&#8230;. you know&#8230;)<br \/>\n8. You will probably have to change type of your sources &#8211; change extension of the source files where you use OpenCV APIs from &#8220;.m&#8221; to &#8220;.mm&#8221;<\/p>\n<p>Now you should be able to use OpenCV routines in your application. But again, for me it was working perfectly on the simulator. But on the iPhone application was crashing right after start. I&#8217;ll investigate this and add an update later.<\/p>\n<p><strong>2. Static library<\/strong><\/p>\n<p>This approach is less convenient in using, but it works on both simulator and hardware. So, let&#8217;s start.<\/p>\n<p>1. To create static library follow these <a onclick=\"javascript:pageTracker._trackPageview('\/outgoing\/ildan.blogspot.com\/2008_07_01_archive.html');\"  href=\"http:\/\/ildan.blogspot.com\/2008_07_01_archive.html\" target=\"_blank\">instructions<\/a>.<br \/>\n2. Now, when you have five *.a files, to make you life easier, put libraries in the separate folder. Then walk through the sources of OpenCV (folders cv, cvaux, cxvore etc.) and copy all the header files to the separate location. Thus, you will have folder (let&#8217;s call it &#8220;OpenCV.lib&#8221;) with all *.a files and subfolder (let say &#8220;hdrs&#8221;), which contains all header files.<br \/>\n3. Go ahead and create new application in the XCode.<br \/>\n4. Add all the OpenCV header files to you project &#8211; right click &#8220;Classes&#8221; group and select &#8220;Add -&gt; Existing Files&#8221; and double-click &#8220;\/&#8230;\/OpenCV.lib\/hdrs&#8221; folder you created on step 2.<br \/>\n5. Somewhere in your code include files cv.h, ml.h and highgui.h.<br \/>\n6. Now double click your target (under &#8220;Targets&#8221; group) and go to the &#8220;Build&#8221; tab.<br \/>\n7. In the &#8220;Linking&#8221; section find option &#8220;Other Linker Flags&#8221; and add paths to your OpenCV library. This field should look like this: &#8220;\/&#8230;\/OpenCV.lib\/libcv.a \/&#8230;\/OpenCV.lib\/libcvaux.a &#8221; and so on.<br \/>\n8. Ok, you are now ready to go!<br \/>\n9. No, stop. Don&#8217;t forget to add libstdc++ library to you project. Other wise you&#8217;ll face compilation issues.<br \/>\n10. Well now you are ready.<\/p>\n<p><strong>Few useful notes.<\/strong><\/p>\n<p>1. OpenCV works with IplImage, while your application will require UIImage for displaying. To convert from IplImage to UIImage you can use following function (thanks to <a onclick=\"javascript:pageTracker._trackPageview('\/outgoing\/www.bitstorm.de\/blog\/2009\/02\/09\/cvimagetocgimage\/');\"  href=\"http:\/\/www.bitstorm.de\/blog\/2009\/02\/09\/cvimagetocgimage\/\">this<\/a> guy for the function):<\/p>\n<pre class=\"cpp:nocontrols:nogutter\">-(CGImageRef)getCGImageFromCVImage:(IplImage*)cvImage\r\n{\r\n\t\/\/ define used variables\r\n\tint height, width, step, channels;\r\n\tuchar *data;\r\n\r\n\t\/\/ get the with and height of the used cvImage\r\n\theight = cvImage-&gt;height;\r\n\twidth = cvImage-&gt;width;\r\n\tstep = cvImage-&gt;widthStep;\r\n\tchannels = cvImage-&gt;nChannels;\r\n\r\n\t\/\/ create the new image with the flipped colors (BGR to RGB)\r\n\tIplImage* imgForUI = 0;\r\n\timgForUI = cvCreateImage(cvSize(width, height), 8, 3);\r\n\tcvConvertImage(cvImage, imgForUI, CV_CVTIMG_SWAP_RB);\r\n\r\n\t\/\/ the data with the flipped colors\r\n\tdata = (uchar *)imgForUI-&gt;imageData;\r\n\r\n\t\/\/ create a CFDataRef\r\n\tCFDataRef imgData = CFDataCreate(NULL, data, imgForUI-&gt;imageSize);\r\n\r\n\t\/\/ create a CGDataProvider with the CFDataRef\r\n\tCGDataProviderRef imgDataProvider = CGDataProviderCreateWithCFData (imgData);\r\n\r\n\t\/\/ create a CGImageRef with the CGDataProvider\r\n\tCGImageRef cgImage = CGImageCreate(width,\r\n\t\t\t\t\t\t\t\t\t   height,\r\n\t\t\t\t\t\t\t\t\t   8,\r\n\t\t\t\t\t\t\t\t\t   8*channels,\r\n\t\t\t\t\t\t\t\t\t   step,\r\n\t\t\t\t\t\t\t\t\t   CGColorSpaceCreateDeviceRGB(),\r\n\t\t\t\t\t\t\t\t\t   kCGImageAlphaNone,\r\n\t\t\t\t\t\t\t\t\t   imgDataProvider,\r\n\t\t\t\t\t\t\t\t\t   NULL,\r\n\t\t\t\t\t\t\t\t\t   NO,\r\n\t\t\t\t\t\t\t\t\t   kCGRenderingIntentDefault);\r\n\r\n\t\/\/ release the CGDataProvider\r\n\tCGDataProviderRelease(imgDataProvider);\r\n\r\n\t\/\/ return the new CGImageRef\r\n\treturn cgImage;\r\n}<\/pre>\n<p>Then, use CGimage you got to create UIImage which can be displayed to the user.<\/p>\n<p>2. If you will try to load image using cvLoadImage on the iPhone, process it with OpenCV (e.g. try to find faces there) and then display it, all you will see is a black rectangle with some color junk at the beginning (by the way face detection will not work on this picture &#8211; 0 object will be found). This is because cvLoadImage does not work properly on the iPhone hardware for some reasons (though, as usual, everything is fine on the simulator). To cure this try to open image using APIs from iPhone SDK and then convert it to the IplImage (<a onclick=\"javascript:pageTracker._trackPageview('\/outgoing\/www.bitstorm.de\/blog\/2009\/02\/12\/more-opencv-tools\/');\"  href=\"http:\/\/www.bitstorm.de\/blog\/2009\/02\/12\/more-opencv-tools\/\">boris<\/a>, thanks again):<\/p>\n<pre class=\"cpp:nocontrols:nogutter\">- (void)manipulateOpenCVImagePixelDataWithCGImage:(CGImageRef)inImage openCVimage:(IplImage *)openCVimage\r\n{\r\n\t\/\/ Create the bitmap context\r\n\tCGContextRef cgctx = [self createARGBBitmapContext:inImage];\r\n\tif (cgctx == NULL)\r\n\t{\r\n\t\t\/\/ error creating context\r\n\t\treturn;\r\n\t}\r\n\r\n\tint height,width,step,channels;\r\n\tuchar *cvdata;\r\n\t\/\/int i,j,k;\r\n\tint x,y;\r\n\r\n\theight = openCVimage-&gt;height;\r\n\twidth = openCVimage-&gt;width;\r\n\tstep = openCVimage-&gt;widthStep;\r\n\tchannels = openCVimage-&gt;nChannels;\r\n\tcvdata = (uchar *)openCVimage-&gt;imageData;\r\n\r\n\tCGRect rect = {{0,0},{width,height}};\r\n\r\n\t\/\/ Draw the image to the bitmap context. Once we draw, the memory\r\n\t\/\/ allocated for the context for rendering will then contain the\r\n\t\/\/ raw image data in the specified color space.\r\n\tCGContextDrawImage(cgctx, rect, inImage);\r\n\r\n\t\/\/ Now we can get a pointer to the image data associated with the bitmap\r\n\t\/\/ context.\r\n\tunsigned char *data = (unsigned char*)CGBitmapContextGetData (cgctx);\r\n\r\n\tif (data != NULL)\r\n\t{\r\n\t\t\/\/int counter = 0;\r\n\t\tfor( y = 0; y &lt; height; ++y )\r\n\t\t{\r\n\t\t\tfor( x = 0; x &lt; width; ++x )\r\n\t\t\t{\r\n\t\t\t\tcvdata[y*step+x*channels+0] = data[(4*y*width)+(4*x)+3];\r\n\t\t\t\tcvdata[y*step+x*channels+1] = data[(4*y*width)+(4*x)+2];\r\n\t\t\t\tcvdata[y*step+x*channels+2] = data[(4*y*width)+(4*x)+1];\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\r\n\t\/\/ When finished, release the context\r\n\tCGContextRelease(cgctx);\r\n\t\/\/ Free image data memory for the context\r\n\tif (data)\r\n\t{\r\n\t\tfree(data);\r\n\t}\r\n\r\n}\r\n\r\n- (CGContextRef)createARGBBitmapContext:(CGImageRef)inImage\r\n{\r\n\tCGContextRef context = NULL;\r\n\tCGColorSpaceRef colorSpace;\r\n\tvoid * bitmapData;\r\n\tint bitmapByteCount;\r\n\tint bitmapBytesPerRow;\r\n\r\n\t\/\/ Get image width, height. We\u00edll use the entire image.\r\n\tsize_t pixelsWide = CGImageGetWidth(inImage);\r\n\tsize_t pixelsHigh = CGImageGetHeight(inImage);\r\n\r\n\t\/\/ Declare the number of bytes per row. Each pixel in the bitmap in this\r\n\t\/\/ example is represented by 4 bytes; 8 bits each of red, green, blue, and\r\n\t\/\/ alpha.\r\n\tbitmapBytesPerRow = (pixelsWide * 4);\r\n\tbitmapByteCount = (bitmapBytesPerRow * pixelsHigh);\r\n\r\n\t\/\/ Use the generic RGB color space.\r\n\tcolorSpace = CGColorSpaceCreateDeviceRGB();\r\n\tif (colorSpace == NULL)\r\n\t{\r\n\t\treturn NULL;\r\n\t}\r\n\r\n\t\/\/ Allocate memory for image data. This is the destination in memory\r\n\t\/\/ where any drawing to the bitmap context will be rendered.\r\n\tbitmapData = malloc( bitmapByteCount );\r\n\tif (bitmapData == NULL)\r\n\t{\r\n\t\tCGColorSpaceRelease( colorSpace );\r\n\t\treturn NULL;\r\n\t}\r\n\r\n\t\/\/ Create the bitmap context. We want pre-multiplied ARGB, 8-bits\r\n\t\/\/ per component. Regardless of what the source image format is\r\n\t\/\/ (CMYK, Grayscale, and so on) it will be converted over to the format\r\n\t\/\/ specified here by CGBitmapContextCreate.\r\n\tcontext = CGBitmapContextCreate (bitmapData,\r\n\t\t\t\t\t\t\t\t\t pixelsWide,\r\n\t\t\t\t\t\t\t\t\t pixelsHigh,\r\n\t\t\t\t\t\t\t\t\t 8, \/\/ bits per component\r\n\t\t\t\t\t\t\t\t\t bitmapBytesPerRow,\r\n\t\t\t\t\t\t\t\t\t colorSpace,\r\n\t\t\t\t\t\t\t\t\t kCGImageAlphaPremultipliedFirst);\r\n\tif (context == NULL)\r\n\t{\r\n\t\tfree (bitmapData);\r\n\t}\r\n\r\n\t\/\/ Make sure and release colorspace before returning\r\n\tCGColorSpaceRelease( colorSpace );\r\n\r\n\treturn context;\r\n}\r\n\r\n- (IplImage *)getCVImageFromCGImage:(CGImageRef)cgImage\r\n{\r\n\tIplImage *newCVImage = cvCreateImage(cvSize(CGImageGetWidth(cgImage), CGImageGetHeight(cgImage)), 8, 3);\r\n\r\n\t[self manipulateOpenCVImagePixelDataWithCGImage:cgImage openCVimage:newCVImage];\r\n\r\n\treturn newCVImage;\r\n}<\/pre>\n<p>3. If you are going to change OpenCV itself, adding option &#8220;&#8211;enable-debug&#8221; might be useful for debugging. But note, that this will reduce performance (it might work up to 1.5 times slower). Also, it worth adding it anyway, since if you will enter some OpenCV API in the XCode debugger it might freeze or crash application. Also, if you are using OpenCV as a static library, make sure that all OpenCV headers, which are added to you project, are up-to-date. Otherwise, application might not work properly.<\/p>\n<p>And now the sad part&#8230;<br \/>\nPerformance of face detection on the iPhone is painful. Processing of VGA image (640&#215;480) with three faces on it takes 6 to 20 seconds (depends on cvHaarDetectObjects parameters). 320&#215;240 image is a bit faster, but still slow &#8211; 1-6 seconds.<\/p>\n<p>Okay, that&#8217;s all, folks.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>This time OpenCV was ported to the Apple iPhone platform. First of all we need to compile OpenCV library itself so that it can be used on the iPhone. There are two ways here: 1. Use OpenCV as a private framework. 2. Compile OpenCV as a static library. First approach looks more comfortable for using, [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[84],"tags":[19,7,22,20,21,6,23],"class_list":["post-37","post","type-post","status-publish","format-standard","hentry","category-opencv","tag-apple","tag-arm","tag-cgimage","tag-iphone","tag-iplimage","tag-opencv","tag-uiimage"],"_links":{"self":[{"href":"http:\/\/www.computer-vision-software.com\/blog\/wp-json\/wp\/v2\/posts\/37","targetHints":{"allow":["GET"]}}],"collection":[{"href":"http:\/\/www.computer-vision-software.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/www.computer-vision-software.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/www.computer-vision-software.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"http:\/\/www.computer-vision-software.com\/blog\/wp-json\/wp\/v2\/comments?post=37"}],"version-history":[{"count":0,"href":"http:\/\/www.computer-vision-software.com\/blog\/wp-json\/wp\/v2\/posts\/37\/revisions"}],"wp:attachment":[{"href":"http:\/\/www.computer-vision-software.com\/blog\/wp-json\/wp\/v2\/media?parent=37"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/www.computer-vision-software.com\/blog\/wp-json\/wp\/v2\/categories?post=37"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/www.computer-vision-software.com\/blog\/wp-json\/wp\/v2\/tags?post=37"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}