opencv - Remove background from Image & take only Image part for save in iOS -
this need achieve:
- take image camera or gallery
- remove background image & save it
- background should black or white
- also need remove shadow along background
result example:
original image
result image
this have tried:
cgfloat colormasking[6]={222,255,222,255,222,255}; cgimageref imageref = cgimagecreatewithmaskingcolors([img cgimage], colormasking); uiimage *resultthumbimage = [uiimage imagewithcgimage:imageref scale:thumbimage.scale orientation:img.imageorientation];
its work on white background. not more effective. need achieve exact result have placed in above images.
i have referred references:
ios how mask image background color
how remove background of image in iphone app?
changing background color of captured image camera white
can me achieve ?
any references or highly appreciated.
thanks in advance.
generally, rule of thumb, more different background color other colors, easier split image fore- , background. in such case, @chris suggested, possible use simple chroma key implementation. below quick implementation of keying described on wikipedia (it's written in c++ translating objective-c should easy):
/** * @brief separate foreground background using simple chroma keying. * * @param imagebgr image monochrome background * @param chromabgr color of background (using channel order bgr , range [0, 255]) * @param tinner inner threshold, color distances below value counted foreground * @param touter outer threshold, color distances above value counted background * * @return mask (0 - background, 255 - foreground, [1, 255] - partially fore- , background) * * details can found on [wikipedia][1]. * * [1]: https://en.wikipedia.org/wiki/chroma_key#programming */ cv::mat1b chromakey( const cv::mat3b & imagebgr, cv::scalar chromabgr, double tinner, double touter ) { // basic outline: // // 1. convert image ycrcb. // 2. measure euclidean distances of color in ycrbr chroma value. // 3. categorize pixels: // * color distances below inner threshold count foreground; mask value = 0 // * color distances above outer threshold count background; mask value = 255 // * color distances between inner , outer threshold linearly interpolated; mask value = [0, 255] assert( tinner <= touter ); // convert ycrcb. assert( ! imagebgr.empty() ); cv::size imagesize = imagebgr.size(); cv::mat3b imageycrcb; cv::cvtcolor( imagebgr, imageycrcb, cv::color_bgr2ycrcb ); cv::scalar chromaycrcb = bgr2ycrcb( chromabgr ); // convert single bgr value ycrcb. // build mask. cv::mat1b mask = cv::mat1b::zeros( imagesize ); const cv::vec3d key( chromaycrcb[ 0 ], chromaycrcb[ 1 ], chromaycrcb[ 2 ] ); ( int y = 0; y < imagesize.height; ++y ) { ( int x = 0; x < imagesize.width; ++x ) { const cv::vec3d color( imageycrcb( y, x )[ 0 ], imageycrcb( y, x )[ 1 ], imageycrcb( y, x )[ 2 ] ); double distance = cv::norm( key - color ); if ( distance < tinner ) { // current pixel part of background. mask( y, x ) = 0; } else if ( distance > touter ) { // current pixel part of foreground. mask( y, x ) = 255; } else { // current pixel partially part both, fore- , background; interpolate linearly. // compute interpolation factor , clip value range [0, 255]. double d1 = distance - tinner; double d2 = touter - tinner; uint8_t alpha = static_cast< uint8_t >( 255. * ( d1 / d2 ) ); mask( y, x ) = alpha; } } } return mask; }
a working code example can found in github gist.
unfortunately, example not stick rule of thumb. since foreground , background vary in intensity difficult (or impossible) find single global set of parameters separation:
black line around object no holes inside object (
tinner=50
,touter=90
)no black line around object holes inside object (
tinner=100
,touter=170
)
so, if cannot change background of images more complicated approach required. however, quick , simple example implementation bit out of scope, may want related areas of image segmentation , alpha matting.
Comments
Post a Comment