PHP:计算图像中的对象组

Posted

技术标签:

【中文标题】PHP:计算图像中的对象组【英文标题】:PHP: Count object groups in image 【发布时间】:2019-11-07 12:01:52 【问题描述】:

我需要自动计算这张图片中的点数。我们可以假设这些点总是红色的(如果有帮助的话,也可以是黑色的)并且在白色背景上总是这个大小。位置和数量经常变化

起初我以为我可以使用 Tesseract OCR 并且可以计算句点或项目符号,但无论我如何操作图像或白名单字符,结果都是空的。

我尝试的另一件事是使用 Imagick,有一个连接组件功能,但在我的测试中,我使用了相同的代码并且没有得到任何结果...

我查看了 OpenCV,但 php 的唯一端口使用主要用中文编写的文档,并且不支持完整的库,因此 Hough Transform 被抛出窗口。

下面的代码:最后,我冒险使用 PHP 读取图像并循环遍历像素并找到某个阈值之外的任何内容,但我一直坚持如何将单个像素实际分组到一个对象。 -- 需要注意的是,尽管没有内存限制和执行时间限制,但我无法让它与全尺寸图像一起使用(即使它们已经按比例缩小)。

我在这上面花了一天半的时间,它看起来很简单,形状一致但没有......

图片如下:

// creating the initial image
  $starting_img = imagecreatefrompng("converted.png");
  //Dimentions
  $imgDims = getimagesize($source_image);
  $scanWidth = $imgDims[0];
  $scanHeight = $imgDims[1];
  //New image
  $final = imagecreatetruecolor($scanWidth,$scanHeight);
  $white = imagecolorallocate($final, 255, 255, 255);
  imagefill($final,0,0,$white);

  $imageData = array();

  for ($y=1; $y < $scanHeight - 1; $y++) 
    // Get First Row, the scan each row col
    $currentRow = array();
    for ($x=1; $x < $scanWidth - 1; $x++) 
      // Get first col in row 1 and check its data
      $rgb = imagecolorat($starting_img,$x,$y);
      $color = array(
        'r' => ($rgb >> 16) & 255,
        'g' => ($rgb >> 8) & 255,
        'b' => $rgb & 255
      );
      $currentCol = array(
        'x' => $x,
        'y' => $y,
        'r' => $color['r'],
        'g' => $color['g'],
        'b' => $color['b'],
      );
      //Is the pixel red?
      // if ($color['r'] > 200 && $color['g'] < 100 && $color['b'] < 100) 
        array_push($currentRow, $currentCol);
      // 
    
    //Does this row have any red pixels?
    // if (count($currentRow) > 1) 
      array_push($imageData, $currentRow);
    // 
  

  foreach ($imageData as $currentRow => $row) 
    foreach ($row as $currentCol => $col) 
      $newColoredPixel  = imagecolorallocate($final,$col['r'],$col['g'],$col['b']);
      // adding the new pixel to the new image
      imagesetpixel($final,$col['x'],$col['y'],$newColoredPixel);
    
  

  file_put_contents('imageData.txt', print_r($imageData, true));

  imagepng($final,"final.png");

  imagedestroy($final);
  imagedestroy($starting_img);

【问题讨论】:

所有像素的白色背景都是纯白色 (255,255,255) 吗?另外,这些点会重叠吗? @bassxzero 是的,所以原图有线条和很多东西。我基本上使用 Imagick 将所有非红色像素替换为白色像素。所以我们可以假设背景总是白色的。至于像素重叠,这是非常罕见的,如果他们这样做,我们不必担心那些一次性 【参考方案1】:

好问题!

如果 blob 不重叠 - 您可以通过公式计算它们:

blob_count = total_blob_area / blob_unit_area

在您的情况下,blob 是一个圆圈,因此公式变为:

blob_count = total_blob_area / (π * r^2)

total_blob_area 只是一个略带红色的像素数,但您必须凭经验找到斑点单位直径。

顺便说一句,只有当图像是 truecolor 类型时,函数 imagecolorat() 才会返回 RGB 值,但是您给定的 PNG 具有索引颜色空间,因此能够从中提取真正的 RGB 值 - 您必须将 imagecolorat() 的输出传递给imagecolorsforindex()。

上面描述的blob计数方法的代码是这样的:

function countBlobs($imfile, $blob_diameter) 

    $blob_area = pi()*pow($blob_diameter/2, 2);

    $im = imagecreatefrompng($imfile);
    list($width, $height, $type, $attr) = getimagesize($imfile);

    $total_blob_area = 0;
    for ($x=0; $x < $width; $x++) 
        for ($y=0; $y < $height; $y++) 
            $rgb = imagecolorat($im, $x, $y);
            $colors = imagecolorsforindex($im, $rgb);
            $avg = ($colors['red']+$colors['green']+$colors['blue'])/3;
            if ($avg < 150) 
            
                $total_blob_area++;
            
        
    

    $blobs = $total_blob_area / $blob_area;

    return round($blobs);


echo ('blobs : ' . countBlobs('countblobs.png', 16));

您可以使用 GIMP 中的距离测量工具找到 Blob 单位直径。但是,如果您的 blob 可以具有不同的形状/大小 - 那么您将需要对 blob 单位面积进行某种平均。

【讨论】:

我忘了说我只考虑过像素计数。我决定不这样做,因为我觉得它可能太不准确了。我会在一个大型数据集上试一试,让你知道它是如何进行的 太棒了。我制作了一个原始图像的 3x3 网格,等于 342 个斑点,公式的结果是 339。对于斑点有多不均匀,这是完全可以接受的,我想我会增加原始分辨率来帮助解决这个问题。谢谢! 不客气。实际上,这是一种近似方法,因为它取决于许多相关参数 - 要分配给斑点的像素的颜色阈值、均匀且相同的斑点形状、不重叠的斑点等。但是尝试一个非常好的做法首先是近似方法,然后在没有明显原因的情况下跳到复杂的方法。顺便说一句,在您的原始图像中,报告了 38 个 blob 的准确计数:-)

以上是关于PHP:计算图像中的对象组的主要内容,如果未能解决你的问题,请参考以下文章

计算图像中的对象

计算二值图像中的前景对象

如何按对象计算熊猫组列中的不同值?

JQ:计算每个组的对象数,用于输入的子集

使用Python,Opencv检测AprilTag

计算机视觉常用算法讲解