检测图像iOS中的黑色像素

时间:2012-01-21 17:39:26

标签: objective-c ios image colors pixel

截至目前,我正在逐个搜索每个像素,检查颜色是否为黑色......如果不是,我会继续查看下一个像素。这是永远的,因为我只能检查约。每秒100像素(加速我的NSTimer冻结应用程序,因为它无法足够快地检查。)所以,无论如何我可以让Xcode返回所有黑色的像素并忽略其他所有因素我只需检查这些像素而不是每个像素。我试图在我的图像上检测到最左边的黑色像素。

这是我目前的代码。

- (void)viewDidLoad {
    timer = [NSTimer scheduledTimerWithTimeInterval: 0.01
                                             target: self
                                           selector:@selector(onTick:)
                                           userInfo: nil repeats:YES];
    y1 = 0;
    x1 = 0;
    initialImage = 0;
    height1 = 0;
    width1 = 0;
}

-(void)onTick:(NSTimer *)timer {
    if (initialImage != 1) {
        /*
        IMAGE INITIALLY GETS SET HERE... "image2.image = [blah blah blah];" took this out for non disclosure reasons
        */
        initialImage = 1;
    }
    //image2 is the image I'm checking the pixels of.
    width1 = (int)image2.size.width;
    height1 = (int)image2.size.height;
    CFDataRef imageData = CGDataProviderCopyData(CGImageGetDataProvider(image2.CGImage));
    const UInt32 *pixels = (const UInt32*)CFDataGetBytePtr(imageData);
    if ( (pixels[(x1+(y1*width1))]) == 0x000000) { //0x000000 is black right?
        NSLog(@"black!");
        NSLog(@"x = %i", x1);
        NSLog(@"y = %i", y1);
    }else {
        NSLog(@"val: %lu", (pixels[(x1+(y1*width1))]));
        NSLog(@"x = %i", x1);
        NSLog(@"y = %i", y1);
        x1 ++;
        if (x1 >= width1) {
            y1 ++;
            x1 = 0;
        }
    }
    if (y1 > height1) {
        /*
        MY UPDATE IMAGE CODE GOES HERE (IMAGE CHANGES EVERY TIME ALL PIXELS HAVE BEEN CHECKED
        */
        y1 = 0;
        x1 = 0;
    }

此外,如果一个像素真的接近黑色而不是完美的黑色...我可以在某处添加误差范围,这样它仍会检测到像95%黑色的像素吗?谢谢!

3 个答案:

答案 0 :(得分:7)

你为什么要使用计时器?为什么不在函数中使用双循环for循环遍历图像中所有可能的x和y坐标?当然,这比仅检查每秒最多100个像素更快。您可能希望外循环中的x(宽度)坐标和内循环中的y(高度)坐标,以便您从左到右一次有效地扫描一列像素,因为您正在尝试查找最左边的黑色像素。

另外,您确定图像中的每个像素都有4字节(Uint32)表示吗?标准位图每像素有3个字节。要检查像素是否接近黑色,您只需分别检查像素中的每个字节,并确保它们都小于某个阈值。

编辑:好的,既然您正在使用UIGetScreenImage,我将假设它是每像素4个字节。

const UInt8 *pixels = CFDataGetBytePtr(imageData);
UInt8 blackThreshold = 10; // or some value close to 0
int bytesPerPixel = 4;
for(int x = 0; x < width1; x++) {
  for(int y = 0; y < height1; y++) {
    int pixelStartIndex = (x + (y * width1)) * bytesPerPixel;
    UInt8 alphaVal = pixels[pixelStartIndex]; // can probably ignore this value
    UInt8 redVal = pixels[pixelStartIndex + 1];
    UInt8 greenVal = pixels[pixelStartIndex + 2];
    UInt8 blueVal = pixels[pixelStartIndex + 3];
    if(redVal < blackThreshold && blueVal < blackThreshold && greenVal < blackThreshold) {
      //This pixel is close to black...do something with it
    }
  }
}

如果事实证明bytesPerPixel为3,则相应地更改该值,从for循环中删除alphaVal,并从红色,绿色和蓝色值的索引中减去1。

此外,我目前的理解是UIGetScreenImage被认为是Apple可能会或可能不会拒绝您使用的私人功能。

答案 1 :(得分:2)

我不是像素级图像处理方面的专家,但我首先想到的是:你为什么要用计时器来做这个?这会产生大量开销并使代码不太清晰。 (我认为这也使它变得线程不安全。)开销不只是来自计时器本身,而是因为你每次都在进行所有的数据设置。

如何使用循环来迭代像素?

此外,您正在泄漏imageData(因为您使用“复制”方法创建它并且永远不会释放它)。目前你正在做这个每个计时器开火(如果你正在处理除最小的图像以外的所有图像,你的imageData可能相当大),所以你可能正在泄漏存储器中。

答案 2 :(得分:0)

你不应该用计时器这样做(或者我无论如何都无法想到!)。

你的影像有多大?在一个循环中合理快速地处理整个图像应该是可行的。