Заставить preg_match_all останавливаться после записи изменений группы

Я пытаюсь определить ширину цветного прямоугольника внутри изображения. Для обработки изображений я использую Imagick для PHP.

Идея заключалась в том, чтобы преобразовать изображение в txt и найти в этом txt регулярное выражение для всех пикселей, имеющих определенный цвет (#00FF00).

Вот пример того, как выглядит этот txt (отрывок, начинающийся со строки 83 столбца пикселей 0):

0,83: (255,255,255,1)  #FFFFFF  graya(255,1)
1,83: (255,255,255,1)  #FFFFFF  graya(255,1)
2,83: (255,255,255,1)  #FFFFFF  graya(255,1)
3,83: (0,255,0,1)  #00FF00  graya(0,1)
4,83: (0,255,0,1)  #00FF00  graya(0,1)
5,83: (0,255,0,1)  #00FF00  graya(0,1)
6,83: (255,255,255,1)  #FFFFFF  graya(255,1)
7,83: (255,255,255,1)  #FFFFFF  graya(255,1)
8,83: (255,255,255,1)  #FFFFFF  graya(255,1)
0,84: (255,255,255,1)  #FFFFFF  graya(255,1)
1,84: (255,255,255,1)  #FFFFFF  graya(255,1)
2,84: (255,255,255,1)  #FFFFFF  graya(255,1)
3,84: (0,255,0,1)  #00FF00  graya(0,1)
4,84: (0,255,0,1)  #00FF00  graya(0,1)
5,84: (0,255,0,1)  #00FF00  graya(0,1)
....

Вот мой код:

$canvasImg = new Imagick("_sources/passepartout/". $deviceName .".png");

$canvasImg->setFormat(txt);

preg_match_all("/(\\d+),(\\d+): \\(0,255,0,1\\)/is", $canvasImg, $colorMatchAll);

$firstPixelX = reset($colorMatch[1]);
$lastPixelX = end($colorMatch[1]);

$canvasWidth = $lastPixelX - $firstPixelX;

Пока это работает нормально, но ужасно медленно, так как находит все пиксели в цветном прямоугольнике, включая полную высоту оси y.

Теперь, когда меня интересует только ширина этого прямоугольника #00FF00, я подумал, что будет быстрее, если регулярное выражение просто найдет первый пиксель с #00FF00, а затем пройдет строку пикселей до конца (строка 83 в моем примере) и останавливается, как только достигает 84-й строки.

Есть ли модификация, которую я мог бы внести в свое регулярное выражение, чтобы оно делало то, что я ищу?


person micharuss    schedule 31.01.2016    source источник
comment
Серьезно, если вам нужна большая скорость, используйте функции обработки изображений вместо.... этого.   -  person Lucas Trzesniewski    schedule 31.01.2016
comment
Я вижу, вас интересует только последнее и первое?   -  person Yehia Awad    schedule 31.01.2016
comment
@яша да, только последний и первый   -  person micharuss    schedule 31.01.2016
comment
@LucasTrzesniewski я пытался, но не нашел ничего, что соответствовало бы моим потребностям   -  person micharuss    schedule 31.01.2016
comment
php.net/manual/en/book.image.php   -  person Lucas Trzesniewski    schedule 31.01.2016
comment
так если я правильно понял для всего процесса у вас будет не начало а конец каждой строки ? например, для строки 83 вам нужен последний и конец, для строки 84 вам нужен последний и конец и т. д. и т. д. или вы хотите только начало и конец всего текста?   -  person Yehia Awad    schedule 31.01.2016
comment
@яша я хочу, чтобы этот цвет отображался только в первом и последнем ряду. остальные строки не имеют значения. но я не знаю, где начинается первая строка. так что в основном найдите первую строку с этим цветом и посмотрите, где она заканчивается в этой строке. тогда остановись.   -  person micharuss    schedule 31.01.2016
comment
у вас есть этот вывод как строковый тип?   -  person Yehia Awad    schedule 31.01.2016
comment
@яша, ты имеешь в виду текстовый файл?   -  person micharuss    schedule 31.01.2016
comment
Во-первых: сделайте это, как сказал @LucasTrzesniewski - используйте правильные функции изображения. Однако вы можете привязать регулярное выражение к началу — ваш первый подход занимает 558 шагов (согласно regex101.com/r /pU7fL1/1), с якорем всего 58 — улучшение на 90% (см. здесь: regex101.com/r/pU7fL1/2)   -  person Jan    schedule 31.01.2016
comment
Спасибо, ребята, функция изображения была бы совершенно предпочтительнее, но, похоже, нет такой, которая способна на то, что я хочу. Но я придумал регулярное выражение, которое делает то, что мне нужно: regex101.com/r/pU7fL1/3   -  person micharuss    schedule 01.02.2016
comment
@micharuss Вы делаете ту же домашнюю работу, что и этот парень: using-imagick-or-other-librar/34956468#34956468" title="php как найти координаты краев изображения с помощью imagick или другой библиотеки"> stackoverflow.com/questions/34939555/   -  person Danack    schedule 01.02.2016


Ответы (1)


Вы можете либо использовать $imagick->trimImage(), а затем $imagick->getImagePage(), чтобы получить местоположение, если прямоугольник — это единственное, что есть на изображении, либо вы можете перебирать пиксели и выполнять собственное обнаружение краев.

$imagick = new \Imagick(realpath($imagePath));
$imageIterator = $imagick->getPixelRegionIterator(0, 0, 
     $imagick->getImageWidth(),
     $imagick->getImageHeight(),
 );

/* Loop through pixel rows */
foreach ($imageIterator as $pixels) {
    /** @var $pixel \ImagickPixel */
    /* Loop through the pixels in the row (columns) */
    foreach ($pixels as $column => $pixel) {
        $red = $pixel->getColorValue(\Imagick::COLOR_RED);
        $green = $pixel->getColorValue(\Imagick::COLOR_GREEN);
        $blue = $pixel->getColorValue(\Imagick::COLOR_BLUE);
        //Do detection here
    }
    /* Sync the iterator, this is important to do on each iteration */
    $imageIterator->syncIterator();
}

$imageIterator->clear();
person Danack    schedule 31.01.2016
comment
спасибо, это сработало для меня! к сожалению, trimImage() не сработал, потому что на изображении много чего, кроме моего цветного прямоугольника... - person micharuss; 01.02.2016