谈谈iOS下图像颜色检测、颜色匹配的解决方法

时间:2022-05-18 16:27:54
最近写一个应用,需要对图像中某一个像素点的颜色进行取样,并检测是否与特定颜色一致或相近,解决的办法如下:

一、像素点颜色取样(代码参考国外一篇文章,在最后列出)

  1. + (UIColor*) getPixelColorAtLocation:(CGPoint)point inImage:(UIImage *)image {  
  2.   
  3.     UIColor* color = nil;  
  4.     CGImageRef inImage = image.CGImage;  
  5.     CGContextRef cgctx = [DetectColour createARGBBitmapContextFromImage:  
  6.     inImage];  
  7.   
  8.     if (cgctx == NULL) { return nil; /* error */ }  
  9.     size_t w = CGImageGetWidth(inImage);  
  10.     size_t h = CGImageGetHeight(inImage);  
  11.     CGRect rect = {{0,0},{w,h}};  
  12.   
  13.     CGContextDrawImage(cgctx, rect, inImage);  
  14.   
  15.     unsigned char* data = CGBitmapContextGetData (cgctx);  
  16.   
  17.     if (data != NULL) {  
  18.        int offset = 4*((w*round(point.y))+round(point.x));  
  19.        int alpha =  data[offset];  
  20.        int red = data[offset+1];  
  21.        int green = data[offset+2];  
  22.        int blue = data[offset+3];  
  23.        NSLog(@"offset: %i colors: RGB A %i %i %i  %i",offset,red,green,  
  24.        blue,alpha);  
  25.   
  26.        NSLog(@"x:%f y:%f", point.x, point.y);  
  27.   
  28.        color = [UIColor colorWithRed:(red/255.0f) green:(green/255.0f) blue:  
  29.        (blue/255.0f) alpha:(alpha/255.0f)];  
  30.     }  
  31.   
  32.     CGContextRelease(cgctx);  
  33.   
  34.     if (data) { free(data); }  
  35.   
  36.     return color;  
  37.   
  38. }  
  39. + (CGContextRef) createARGBBitmapContextFromImage:(CGImageRef) inImage {  
  40.   
  41. CGContextRef    context = NULL;  
  42.   
  43. CGColorSpaceRef colorSpace;  
  44.   
  45. void *          bitmapData;  
  46.   
  47. int             bitmapByteCount;  
  48.   
  49. int             bitmapBytesPerRow;  
  50.   
  51. size_t pixelsWide = CGImageGetWidth(inImage);  
  52.   
  53. size_t pixelsHigh = CGImageGetHeight(inImage);  
  54.   
  55. bitmapBytesPerRow   = (pixelsWide * 4);  
  56.   
  57. bitmapByteCount     = (bitmapBytesPerRow * pixelsHigh);  
  58.   
  59. colorSpace = CGColorSpaceCreateDeviceRGB();  
  60.   
  61. if (colorSpace == NULL)  
  62.   
  63. {  
  64.   
  65. fprintf(stderr, "Error allocating color space\n");  
  66.   
  67. return NULL;  
  68.   
  69. }  
  70.   
  71. bitmapData = malloc( bitmapByteCount );  
  72.   
  73. if (bitmapData == NULL)  
  74.   
  75. {  
  76.   
  77. fprintf (stderr, "Memory not allocated!");  
  78.   
  79. CGColorSpaceRelease( colorSpace );  
  80.   
  81. return NULL;  
  82.   
  83. }      
  84.   
  85. context = CGBitmapContextCreate (bitmapData,  
  86.   
  87. pixelsWide,  
  88.   
  89. pixelsHigh,  
  90.   
  91. 8,        
  92.   
  93. bitmapBytesPerRow,  
  94.   
  95. colorSpace,  
  96.   
  97. kCGImageAlphaPremultipliedFirst);  
  98.   
  99. if (context == NULL)  
  100.   
  101. {  
  102.   
  103. free (bitmapData);  
  104.   
  105. fprintf (stderr, "Context not created!");  
  106.   
  107. }  
  108.   
  109. CGColorSpaceRelease( colorSpace );  
  110.   
  111. return context;  
  112.   
  113. }  

二、颜色匹配计算
一是精确的匹配,通过生成两个CGColor,利用CGColorEqualToColor函数进行对比即可,如下:
  1. //生成采样对照颜色(黑色)  
  2.  UIColor* sampleColor = [UIColor colorWithRed:(0/255.0f) green:(0/255.0f)  
  3.  blue:(0/255.0f) alpha:(255/255.0f)];  
  4. //比较  
  5.  if (CGColorEqualToColor(detectedColor.CGColor, sampleColor.CGColor)) {  
  6.    //处理  
  7. }  

二是模糊的匹配,在RGB色彩空间下, 每个像素点的颜色有四个通道(R, G, B, Alpha),比较
两个颜色是否一致的方法,可以通过比较其向量的方式来进行,如下:
  1. //获取颜色分量  
  2. const CGFloat* components = CGColorGetComponents(detectedColor.CGColor);  
  3. CGFloat Red, Green, Blue, Alpha;  
  4. Alpha = components[0];  
  5. Red = components[0+1];  
  6. ....  
  7. //向量比较  
  8. float difference = pow( pow((red1 - red2), 2) + pow((green1 - green2), 2) +  
  9. pow((blue1 - blue2), 2), 0.5 );  

至于阀值的设定,就需要大家根据实际情况来调整了,一般可设置为85,如果严格一点,则小一点;宽松一点,则可以设大一点。

参考文章: http://www.markj.net/iphone-uiimage-pixel-color/