iOS如何實現(xiàn)去除圖片背景顏色

這篇文章主要為大家展示了“iOS如何實現(xiàn)去除圖片背景顏色”,內(nèi)容簡而易懂,條理清晰,希望能夠幫助大家解決疑惑,下面讓小編帶領(lǐng)大家一起研究并學(xué)習(xí)一下“iOS如何實現(xiàn)去除圖片背景顏色”這篇文章吧。

成都創(chuàng)新互聯(lián)于2013年創(chuàng)立,是專業(yè)互聯(lián)網(wǎng)技術(shù)服務(wù)公司,擁有項目成都網(wǎng)站制作、成都做網(wǎng)站、外貿(mào)營銷網(wǎng)站建設(shè)網(wǎng)站策劃,項目實施與項目整合能力。我們以讓每一個夢想脫穎而出為使命,1280元明山做網(wǎng)站,已為上家服務(wù),為明山各地企業(yè)和個人服務(wù),聯(lián)系電話:028-86922220

實際項目場景:去除圖片的純白色背景圖,獲得一張透明底圖片用于拼圖功能

介紹兩種途徑的三種處理方式,具體性能鶸并未對比,如果有大佬能告知,不勝感激。

Core Image Core Graphics/Quarz 2D Core Image

Core Image是一個很強大的框架。它可以讓你簡單地應(yīng)用各種濾鏡來處理圖像,比如修改鮮艷程度,色澤,或者曝光。 它利用GPU(或者CPU)來非常快速、甚至實時地處理圖像數(shù)據(jù)和視頻的幀。并且隱藏了底層圖形處理的所有細(xì)節(jié),通過提供的API就能簡單的使用了,無須關(guān)心OpenGL或者OpenGL ES是如何充分利用GPU的能力的,也不需要你知道GCD在其中發(fā)揮了怎樣的作用,Core Image處理了全部的細(xì)節(jié)。

iOS如何實現(xiàn)去除圖片背景顏色

在蘋果官方文檔Core Image Programming Guide中,提到了Chroma Key Filter Recipe對于處理背景的范例

其中使用了HSV顏色模型,因為HSV模型,對于顏色范圍的表示,相比RGB更加友好。

大致過程處理過程:

創(chuàng)建一個映射希望移除顏色值范圍的立方體貼圖cubeMap,將目標(biāo)顏色的Alpha置為0.0f 使用CIColorCube濾鏡和cubeMap對源圖像進(jìn)行顏色處理獲取到經(jīng)過CIColorCube處理的Core Image對象CIImage,轉(zhuǎn)換為Core Graphics中的CGImageRef對象,通過imageWithCGImage:獲取結(jié)果圖片

注意:第三步中,不可以直接使用imageWithCIImage:,因為得到的并不是一個標(biāo)準(zhǔn)的UIImage,如果直接拿來用,會出現(xiàn)不顯示的情況。

- (UIImage *)removeColorWithMinHueAngle:(float)minHueAngle maxHueAngle:(float)maxHueAngle image:(UIImage *)originalImage{
 CIImage *image = [CIImage imageWithCGImage:originalImage.CGImage];
 CIContext *context = [CIContext contextWithOptions:nil];// kCIContextUseSoftwareRenderer : CPURender
 /** 注意
 * UIImage 通過CIimage初始化,得到的并不是一個通過類似CGImage的標(biāo)準(zhǔn)UIImage
 * 所以如果不用context進(jìn)行渲染處理,是沒辦法正常顯示的
 */
 CIImage *renderBgImage = [self outputImageWithOriginalCIImage:image minHueAngle:minHueAngle maxHueAngle:maxHueAngle];
 CGImageRef renderImg = [context createCGImage:renderBgImage fromRect:image.extent];
 UIImage *renderImage = [UIImage imageWithCGImage:renderImg];
 return renderImage;
}
struct CubeMap {
 int length;
 float dimension;
 float *data;
};
- (CIImage *)outputImageWithOriginalCIImage:(CIImage *)originalImage minHueAngle:(float)minHueAngle maxHueAngle:(float)maxHueAngle{
 
 struct CubeMap map = createCubeMap(minHueAngle, maxHueAngle);
 const unsigned int size = 64;
 // Create memory with the cube data
 NSData *data = [NSData dataWithBytesNoCopy:map.data
   length:map.length
   freeWhenDone:YES];
 CIFilter *colorCube = [CIFilter filterWithName:@"CIColorCube"];
 [colorCube setValue:@(size) forKey:@"inputCubeDimension"];
 // Set data for cube
 [colorCube setValue:data forKey:@"inputCubeData"];
 
 [colorCube setValue:originalImage forKey:kCIInputImageKey];
 CIImage *result = [colorCube valueForKey:kCIOutputImageKey];
 
 return result;
}
struct CubeMap createCubeMap(float minHueAngle, float maxHueAngle) {
 const unsigned int size = 64;
 struct CubeMap map;
 map.length = size * size * size * sizeof (float) * 4;
 map.dimension = size;
 float *cubeData = (float *)malloc (map.length);
 float rgb[3], hsv[3], *c = cubeData;
 
 for (int z = 0; z < size; z++){
 rgb[2] = ((double)z)/(size-1); // Blue value
 for (int y = 0; y < size; y++){
 rgb[1] = ((double)y)/(size-1); // Green value
 for (int x = 0; x < size; x ++){
 rgb[0] = ((double)x)/(size-1); // Red value
 rgbToHSV(rgb,hsv);
 // Use the hue value to determine which to make transparent
 // The minimum and maximum hue angle depends on
 // the color you want to remove
 float alpha = (hsv[0] > minHueAngle && hsv[0] < maxHueAngle) ? 0.0f: 1.0f;
 // Calculate premultiplied alpha values for the cube
 c[0] = rgb[0] * alpha;
 c[1] = rgb[1] * alpha;
 c[2] = rgb[2] * alpha;
 c[3] = alpha;
 c += 4; // advance our pointer into memory for the next color value
 }
 }
 }
 map.data = cubeData;
 return map;
}

rgbToHSV在官方文檔中并沒有提及,筆者在下文中提到的大佬的博客中找到了相關(guān)轉(zhuǎn)換處理。感謝

void rgbToHSV(float *rgb, float *hsv) {
 float min, max, delta;
 float r = rgb[0], g = rgb[1], b = rgb[2];
 float *h = hsv, *s = hsv + 1, *v = hsv + 2;
 min = fmin(fmin(r, g), b );
 max = fmax(fmax(r, g), b );
 *v = max;
 delta = max - min;
 if( max != 0 )
 *s = delta / max;
 else {
 *s = 0;
 *h = -1;
 return;
 }
 if( r == max )
 *h = ( g - b ) / delta;
 else if( g == max )
 *h = 2 + ( b - r ) / delta;
 else
 *h = 4 + ( r - g ) / delta;
 *h *= 60;
 if( *h < 0 )
 *h += 360;
}

接下來我們試一下,去除綠色背景的效果如何

iOS如何實現(xiàn)去除圖片背景顏色

我們可以通過使用HSV工具,確定綠色HUE值的大概范圍為50-170

調(diào)用一下方法試一下

[[SPImageChromaFilterManager sharedManager] removeColorWithMinHueAngle:50 maxHueAngle:170 image:[UIImage imageWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"nb" ofType:@"jpeg"]]]

效果

iOS如何實現(xiàn)去除圖片背景顏色

效果還可以的樣子。

如果認(rèn)真觀察HSV模型的同學(xué)也許會發(fā)現(xiàn),我們通過指定色調(diào)角度(Hue)的方式,對于指定灰白黑顯得無能為力。我們不得不去用飽和度(Saturation)和明度(Value)去共同判斷,感興趣的同學(xué)可以在代碼中判斷Alpha float alpha = (hsv[0] > minHueAngle && hsv[0] < maxHueAngle) ? 0.0f: 1.0f;那里試一下效果。(至于代碼中為啥RGB和HSV這么轉(zhuǎn)換,請百度他們的轉(zhuǎn)換,因為鶸筆者也不懂。哎,鶸不聊生)

對于Core Image感興趣的同學(xué),請移步大佬的系列文章

iOS8 Core Image In Swift:自動改善圖像以及內(nèi)置濾鏡的使用

iOS8 Core Image In Swift:更復(fù)雜的濾鏡

iOS8 Core Image In Swift:人臉檢測以及馬賽克

iOS8 Core Image In Swift:視頻實時濾鏡

Core Graphics/Quarz 2D

上文中提到的基于OpenGlCore Image顯然功能十分強大,作為視圖另一基石的Core Graphics同樣強大。對他的探究,讓鶸筆者更多的了解到圖片的相關(guān)知識。所以在此處總結(jié),供日后查閱。

如果對探究不感興趣的同學(xué),請直接跳到文章最后 Masking an Image with Color 部分

Bitmap

iOS如何實現(xiàn)去除圖片背景顏色

在Quarz 2D官方文檔中,對于BitMap有如下描述:

A bitmap image (or sampled image) is an array of pixels (or samples). Each pixel represents a single point in the image. JPEG, TIFF, and PNG graphics files are examples of bitmap images.

32-bit and 16-bit pixel formats for CMYK and RGB color spaces in Quartz 2D

回到我們的需求,對于去除圖片中的指定顏色,如果我們能夠讀取到每個像素上的RGBA信息,分別判斷他們的值,如果符合目標(biāo)范圍,我們將他的Alpha值改為0,然后輸出成新的圖片,那么我們就實現(xiàn)了類似上文中cubeMap的處理方式。

強大的Quarz 2D為我們提供了實現(xiàn)這種操作的能力,下面請看代碼示例:

- (UIImage *)removeColorWithMaxR:(float)maxR minR:(float)minR maxG:(float)maxG minG:(float)minG maxB:(float)maxB minB:(float)minB image:(UIImage *)image{
 // 分配內(nèi)存
 const int imageWidth = image.size.width;
 const int imageHeight = image.size.height;
 size_t bytesPerRow = imageWidth * 4;
 uint32_t* rgbImageBuf = (uint32_t*)malloc(bytesPerRow * imageHeight);
 // 創(chuàng)建context
 CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();// 色彩范圍的容器
 CGContextRef context = CGBitmapContextCreate(rgbImageBuf, imageWidth, imageHeight, 8, bytesPerRow, colorSpace,kCGBitmapByteOrder32Little | kCGImageAlphaNoneSkipLast);
 CGContextDrawImage(context, CGRectMake(0, 0, imageWidth, imageHeight), image.CGImage);
 // 遍歷像素
 int pixelNum = imageWidth * imageHeight;
 uint32_t* pCurPtr = rgbImageBuf;
 for (int i = 0; i < pixelNum; i++, pCurPtr++)
 {
 uint8_t* ptr = (uint8_t*)pCurPtr;
 if (ptr[3] >= minR && ptr[3] <= maxR &&
 ptr[2] >= minG && ptr[2] <= maxG &&
 ptr[1] >= minB && ptr[1] <= maxB) {
 ptr[0] = 0;
 }else{
 printf("\n---->ptr0:%d ptr1:%d ptr2:%d ptr3:%d<----\n",ptr[0],ptr[1],ptr[2],ptr[3]);
 }
 }
 // 將內(nèi)存轉(zhuǎn)成image
 CGDataProviderRef dataProvider =CGDataProviderCreateWithData(NULL, rgbImageBuf, bytesPerRow * imageHeight, nil);
 CGImageRef imageRef = CGImageCreate(imageWidth, imageHeight,8, 32, bytesPerRow, colorSpace,kCGImageAlphaLast |kCGBitmapByteOrder32Little, dataProvider,NULL,true,kCGRenderingIntentDefault);
 CGDataProviderRelease(dataProvider);
 UIImage* resultUIImage = [UIImage imageWithCGImage:imageRef]; 
 // 釋放
 CGImageRelease(imageRef);
 CGContextRelease(context);
 CGColorSpaceRelease(colorSpace);
 return resultUIImage;
}

還記得我們在Core Image中提到的HSV模式的弊端嗎?那么Quarz 2D則是直接利用RGBA的信息進(jìn)行處理,很好的規(guī)避了對黑白色不友好的問題,我們只需要設(shè)置一下RGB的范圍即可(因為黑白色在RGB顏色模式中,很好確定),我們可以大致封裝一下。如下

- (UIImage *)removeWhiteColorWithImage:(UIImage *)image{
 return [self removeColorWithMaxR:255 minR:250 maxG:255 minG:240 maxB:255 minB:240 image:image];
}
- (UIImage *)removeBlackColorWithImage:(UIImage *)image{
 return [self removeColorWithMaxR:15 minR:0 maxG:15 minG:0 maxB:15 minB:0 image:image];
}

看一下我們對于白色背景的處理效果對比

iOS如何實現(xiàn)去除圖片背景顏色

看起來似乎還不錯,但是對于紗質(zhì)的衣服,就顯得很不友好??匆幌鹿P者做的幾組圖片的測試

iOS如何實現(xiàn)去除圖片背景顏色

很顯然,如果不是白色背景,“衣衫襤褸”的效果非常明顯。這個問題,在筆者嘗試的三種方法中,無一幸免,如果哪位大佬知道好的處理方法,而且能告訴鶸,將不勝感激。(先放倆膝蓋在這兒)

除了上述問題外,這種對比每個像素的方法,讀取出來的數(shù)值會同作圖時出現(xiàn)誤差。但是這種誤差肉眼基本不可見。

iOS如何實現(xiàn)去除圖片背景顏色

如下圖中,我們作圖時,設(shè)置的RGB值分別為100/240/220 但是通過CG上述處理時,讀取出來的值則為92/241/220。對比圖中的“新的”“當(dāng)前”,基本看不出色差。這點小問題各位知道就好,對實際去色效果影響并不大

iOS如何實現(xiàn)去除圖片背景顏色

Masking an Image with Color

筆者嘗試過理解并使用上一種方法后,在重讀文檔時發(fā)現(xiàn)了這個方法,簡直就像是發(fā)現(xiàn)了Father Apple的恩賜。直接上代碼

- (UIImage *)removeColorWithMaxR:(float)maxR minR:(float)minR maxG:(float)maxG minG:(float)minG maxB:(float)maxB minB:(float)minB image:(UIImage *)image{
 const CGFloat myMaskingColors[6] = {minR, maxR, minG, maxG, minB, maxB};
 CGImageRef ref = CGImageCreateWithMaskingColors(image.CGImage, myMaskingColors);
 return [UIImage imageWithCGImage:ref];
 
}

以上是“iOS如何實現(xiàn)去除圖片背景顏色”這篇文章的所有內(nèi)容,感謝各位的閱讀!相信大家都有了一定的了解,希望分享的內(nèi)容對大家有所幫助,如果還想學(xué)習(xí)更多知識,歡迎關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道!

網(wǎng)站題目:iOS如何實現(xiàn)去除圖片背景顏色
文章路徑:http://muchs.cn/article24/jpgjce.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供服務(wù)器托管外貿(mào)建站、面包屑導(dǎo)航、虛擬主機手機網(wǎng)站建設(shè)

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)

小程序開發(fā)