Обнаружить черный пиксель в изображении iOS - PullRequest
2 голосов
/ 21 января 2012

На данный момент я ищу каждый пиксель 1 на 1, проверяя цвет и проверяя, черный ли он ... если нет, я перехожу к следующему пикселю. Это займет вечность, так как я могу проверить только ок. 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 ]

7 голосов
/ 21 января 2012

Почему вы вообще используете таймер?Почему бы просто не иметь двойной цикл 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, измените это значение соответствующим образом, удалите alphaVal из цикла for и вычтите 1 из индексовкрасного, зеленого и синего значений.

Кроме того, в настоящее время я понимаю, что UIGetScreenImage считается частной функцией, которую Apple может или не может отклонить вас за использование.

2 голосов
/ 21 января 2012

Я не эксперт по обработке изображений на уровне пикселей, но моя первая мысль: почему вы используете таймер для этого?Это влечет за собой много накладных расходов и делает код менее понятным для чтения.(Я думаю, что это также делает его поточно-небезопасным.) Затраты не только от самого таймера, но и потому, что вы каждый раз выполняете всю настройку данных.

Как насчет использования цикла вместо итерации попиксели?

Кроме того, у вас есть утечка imageData (так как вы создаете его методом «Копировать» и никогда не выпускаете его).В настоящее время вы делаете это один раз за время срабатывания таймера (и ваши imageData, вероятно, довольно большие, если вы работаете со всеми изображениями, кроме самых маленьких), поэтому вы, вероятно, теряете тонн памяти.

0 голосов
/ 21 января 2012

Нет способа, которым вы должны делать это с таймером (или без причины, о которой я все равно могу думать!).

Насколько велики ваши изображения?Должно быть достаточно эффективно обрабатывать все изображение за один цикл.

...