gpt4 book ai didi

php - 计算图像中任意颜色质心并将其提供给 PHP 的最快方法

转载 作者:行者123 更新时间:2023-12-02 17:27:02 24 4
gpt4 key购买 nike

我正在寻找基于图像中任意颜色计算方向矢量的最快方法(Rpi 相机,但现在可以使用 JPEG 文件进行测试),也就是跟踪彩球项目。请注意,生成的向量(或质心坐标等)需要传递给 PHP 以执行程序,因此我正在寻找的解决方案需要以 PHP 结尾,但之前可以是任何东西,因为它可以在Windows 和 Linux。

考虑输入 JPEG 图像:

enter image description here

这是我所追求的 2 个示例方向向量,它们是基于 1)蓝绿色输入和 2)紫色输入获得的。显然,一次只会询问 1 个向量,我将 2 个用于在 1 个图像中演示多个示例,但一次总是只有 1 个向量。请注意,生成的向量(“v”)被标准化为 -1.0(底部/左侧)到 +1.0(底部/右侧),因此零是图片的中间。

enter image description here

以下是我迄今为止实现/测试的各种解决方案以及整个过程需要多少时间,基于 960x640 JPEG 图片,但实现的解决方案将与 Rpi 相机输入相关联,我还没有相机所以在相机从中国运到之前,我使用 JPEG 图像。

1) 2700ms :使用与 PHP 捆绑的 GD2,for 循环遍历每个像素,在 XY 数组中推送匹配 ~10% RGB 值的像素,平均 XY 数组,计算/归一化来自 XY 数组的方向向量。

$arr_matching_pixels = array('arr_x' => array(), 'arr_y' => array());
for($y = 0; $y < $h - 1; $y++){
for($x = 0; $x < $w - 1; $x++){
$arr_pixel = imagecolorsforindex($img, imagecolorat($img, $x, $y));
if(abs($arr_pixel['red'] - $arr_seek_color['red']) < 30){
if(abs($arr_pixel['green'] - $arr_seek_color['green']) < 30){
if(abs($arr_pixel['blue'] - $arr_seek_color['blue']) < 30){
array_push($arr_matching_pixels['arr_x'], $x);
array_push($arr_matching_pixels['arr_y'], $y);
}
}
}
}
}
// Compute centroid of color... etc...

2) 700ms : 与 #1 相同,只是首先使用 imagecreatefromjpeg('_test_cam_img.jpg'); 将 Canvas 大小调整 50%(可接受的损失)

3) 560ms :与 #2 相同,除了使用带有像素迭代器循环的 ImageMagick 来读取像素
$imagick = new Imagick(realpath($o_img));
$arr_matching_pixels = array('arr_x' => array(), 'arr_y' => array());
$arr_pixel = array();
$iterator = $imagick->getPixelIterator();
foreach($iterator as $y => $pixels){
foreach($pixels as $x => $pixel){
$arr_pixel = $pixel->getColor();
if(abs($arr_pixel['r'] - $arr_seek_color['red']) < 30){
if(abs($arr_pixel['g'] - $arr_seek_color['green']) < 30){
if(abs($arr_pixel['b'] - $arr_seek_color['blue']) < 30){
array_push($arr_matching_pixels['arr_x'], $x);
array_push($arr_matching_pixels['arr_y'], $y);
}
}
}
}
}
// Compute centroid of color... etc...

4) 340ms :通过 exec() 函数调用系统的 ImageMagick 二进制文件,将图像位置、色度/颜色键、resize by 50% 参数、10% 模糊参数和 sparse-color: 修饰符传递给它以提取文本 ( CSV-like) 列出所需像素的表示,然后使用 PHP 循环遍历每一行,分解逗号并推送 XY 数组中的所有像素,平均 XY 数组,计算/归一化来自 XY 数组的方向向量。我注意到调用 exec() 证明比直接从 Windows 命令行执行相同的命令要慢得多。
$imagick = new Imagick(realpath($o_img));
$out = exec('"E:\Users\Ben\Roaming Apps\imagemagick-6.9.3\convert" E:\wamp64\www\test_cam_img.jpg -resize 50% -fuzz 10% +transparent rgb(' . $arr_seek_color['red'] . ',' . $arr_seek_color['green'] . ',' . $arr_seek_color['blue'] . ') sparse-color:');
$arr_lines = explode(' ', $out);
$arr_matching_pixels = array('arr_x' => array(), 'arr_y' => array());
foreach($arr_lines as $str_line){
$arr_xy_coords = explode(',', $str_line);
array_push($arr_matching_pixels['arr_x'], $arr_xy_coords[0]);
array_push($arr_matching_pixels['arr_y'], $arr_xy_coords[1]);
}
// Compute centroid of color... etc...

5) 32ms :PHP 创建一个包含图像路径和色度/颜色键的“输入”文本文件,并开始循环,直到它读取一个“输出”文本文件。 python+OpenCV 脚本已经/总是运行一个(可停止的)无限循环,不断寻找一个“in”文本文件,当它存在时,它会读取它,分解值,使用 HSV 值 ~10% 制作一个 1 位掩码(cv2.inRange) 来自“in”文件,然后使用 cv2.findNonZero(mask) 创建一个数组并计算数组平均值并将其写入 PHP 立即读取的包含方向向量值的“out”文本文件。这是迄今为止我发现的最快的方法,但它很尴尬,因为这意味着 python 脚本必须在 CRONJOB 中编程,并在崩溃时在单个实例中监控/重新启动。
file_put_contents('_avg_color_coords_in.txt', $o_img . "\n" . $arr_seek_color['h'] . ',' . $arr_seek_color['s'] . ',' . $arr_seek_color['l']);

$starttime = time();
while((time() - $starttime) < 5){ // Max 5 seconds (exaggerated)
if(file_exists('_avg_color_coords_out.txt')){
$dir_vector = (float) file_get_contents('_avg_color_coords_out.txt');
if(!@unlink('_avg_color_coords_out.txt')){
sleep(1);
unlink('_avg_color_coords_out.txt');
}
break;
}
usleep(2000);
}
// $dir_vector ("v", the centroid of the color) is already computed by Python


// ---------- PYTHON SCRIPT ----------
import math
import cv2
import numpy as np
import os
import time

#cap = cv2.VideoCapture(0)

#while (1):
# _, frame = cap.read()
if(os.path.exists('_avg_color_coords_stop.txt')):
exit()
while not os.path.exists('_avg_color_coords_in.txt'):
time.sleep(0.002)
f = open('_avg_color_coords_in.txt', 'r')
imgsrc = f.readline().rstrip('\n')
rgbcol = [int(x) for x in f.readline().rstrip('\n').split(',')]
frame = cv2.imread(imgsrc)
h, w = frame.shape[:2]

hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV)
hfacl = rgbcol[0] / 360 * 180 * 0.95
hfach = rgbcol[0] / 360 * 180 * 1.05
sfacl = rgbcol[1] / 100 * 255 * 0.9
sfach = rgbcol[1] / 100 * 255 * 1.1
vfacl = rgbcol[2] / 100 * 255 * 0.9
vfach = rgbcol[2] / 100 * 255 * 1.1
lower_color = np.array([hfacl, sfacl, vfacl]) # 0..180, 0..255, 0..255 not percentage!
upper_color = np.array([hfach, sfach, vfach]) # 0..180, 0..255, 0..255 not percentage!
mask = cv2.inRange(hsv, lower_color, upper_color)
#cv2.imshow('mask', mask)

points = cv2.findNonZero(mask)
if(points.any()):
avg = np.mean(points, axis=0)
else:
avg = [0,0]
#print(avg)

v = -math.atan(((w * 0.5) - avg[0][0]) / (h - avg[0][1])) / (3.1415 * 0.5);
f2 = open('_avg_color_coords_out.txt', 'w+')
f2.write("%s" % str(v))

# k = cv2.waitKey(5) & 0xff
# if k == 27:
# break

#cv2.destroyAllWindows()
#cap.release()

f2.close()
f.close()
os.remove('_avg_color_coords_in.txt')


6) 38ms : 与 #5 相同,只是首先将 Canvas 的大小调整 50%(可接受的损失),这似乎根本没有加快速度,甚至有点适得其反。

有没有更快的方法或者这是最优的?这将在 900mhz Rpi 上每秒运行一次,因此需要快速。我认为 900mhz CPU 上的 30ms 将在 150-200ms 左右(尚未测试,等待相机发货)

最佳答案

我快速进入 php-vips :

#!/usr/bin/env php
<?php

require __DIR__ . '/vendor/autoload.php';

use Jcupitt\Vips;

$image = Vips\Image::newFromFile($argv[1], ['access' => 'sequential']);

# Target colour in RGB.
$target = [50, 10, 100];

# Select pixels where all bands are less than 10 away from the target.
# (and render it to memory ... we'll be reusing this mask image).
# The mask image will have one band with 0 for false and 255 for true.
$mask = $image->subtract($target)->abs()->less(10)->bandand()->copyMemory();

# The number of set pixels in the mask.
$n_set = $mask->avg() * $mask->width * $mask->height / 255;

# Handy for debugging: uncomment to write the mask image for inspection.
# $mask->writeToFile("x.png");

# Make a two-band image where band 0 is x coordinates and band 1 is y
# coordinates.
$coords = Vips\Image::xyz($mask->width, $mask->height);

# Make an indexed histogram: sum $coords at each position.
$pos = $coords->hist_find_indexed($mask);

# fetch the sum of the 255 value (true) pixels
[$x_sum, $y_sum] = $pos->getpoint(255, 0);

echo("x = " . $x_sum / $n_set . "\n");
echo("y = " . $y_sum / $n_set . "\n");

我可以这样运行它:
$ time ./locate-rgb.php ~/pics/x.jpg
x = 483.375
y = 487.75
real 0m0.079s
user 0m0.085s
sys 0m0.022s

所以在这台普通的笔记本电脑上大约需要 80 毫秒。这包括 PHP 启动和关闭,以及解压缩 JPG 图像。

这只适用于非常受限的照明和相机设置,但也许没关系?让球检测更漂亮很容易,但当然会减慢一点。

关于php - 计算图像中任意颜色质心并将其提供给 PHP 的最快方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58649231/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com