图像背景检测及处理 相关资料整理 图片编辑软件:Photoshop、Gimp、Picsart、Snapseed、ImageMagick。 Resythesizer(正确的应该是 Resynthesizer)
if args.algo == 'MOG2':
backSub = cv.createBackgroundSubtractorMOG2()
else:
backSub = cv.createBackgroundSubtractorKNN()
CVzone 是一个计算机视觉包,可以让我们轻松运行像人脸检测、手部跟踪、姿势估计等,以及图像处理和其他 AI 功能。它的核心是使用 OpenCV 和 MediaPipe 库。
ret, thresh1 = cv2.threshold(img, 170, 255, cv2.THRESH_BINARY)
与二元阈值法不同,该方法根据像素值的小周围区域来确定其阈值。这种方法也有两种类型:
th2 = cv2.adaptiveThreshold(img, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C,
cv2.THRESH_BINARY, 11, 2)
/** @brief 自适应二值化
*@param _src 要二值化的灰度图
*@param _dst 二值化后的图
*@param maxValue 二值化后要设置的那个值
*@param method 块计算的方法(ADAPTIVE_THRESH_MEAN_C 平均值,ADAPTIVE_THRESH_GAUSSIAN_C 高斯分布加权和)
*@param type 二值化类型(CV_THRESH_BINARY 大于为最大值,CV_THRESH_BINARY_INV 小于为最大值)
*@param blockSize 块大小(奇数,大于 1)
*@param delta 差值(负值也可以)
*/
void cv::adaptiveThreshold(InputArray _src, OutputArray _dst, double maxValue,
int method, int type, int blockSize, double delta)
{
Mat src = _src.getMat();
// 原图必须是单通道无符号 8 位
CV_Assert(src.type() == CV_8UC1);
// 块大小必须大于 1,并且是奇数
CV_Assert(blockSize % 2 == 1 && blockSize > 1);
Size size = src.size();
// 构建与原图像相同的图像
_dst.create(size, src.type());
Mat dst = _dst.getMat();
if (maxValue < 0)
{
// 二值化后值小于 0,图像都为 0
dst = Scalar(0);
return;
}
// 用于比较的值
Mat mean;
if (src.data != dst.data)
mean = dst;
if (method == ADAPTIVE_THRESH_MEAN_C)
// 计算平均值作为比较值
boxFilter(src, mean, src.type(), Size(blockSize, blockSize),
Point(-1, -1), true, BORDER_REPLICATE);
else if (method == ADAPTIVE_THRESH_GAUSSIAN_C)
// 计算高斯分布和作为比较值
GaussianBlur(src, mean, Size(blockSize, blockSize), 0, 0, BORDER_REPLICATE);
else
CV_Error(CV_StsBadFlag, "Unknown/unsupported adaptive threshold method");
int i, j;
// 将 maxValue 夹到 [0,255] 的 uchar 范围区间,用作二值化后的值
uchar imaxval = saturate_cast<uchar>(maxValue);
// 根据二值化类型计算 delta 值
int idelta = type == THRESH_BINARY ? cvCeil(delta) : cvFloor(delta);
// 计算生成每个像素差对应的值表格,以后查表就可以。但像素差范围为什么是 768,我确实认为 512 已经够了
uchar tab[768];
if (type == CV_THRESH_BINARY)
for (i = 0; i < 768; i++)
// i = src[j] - mean[j] + 255
// i - 255 > -idelta ? imaxval : 0
// = src[j] - mean[j] + 255 -255 > -idelta ? imaxval : 0
// = src[j] > mean[j] - idelta ? imaxval : 0
tab[i] = (uchar)(i - 255 > -idelta ? imaxval : 0);
else if (type == CV_THRESH_BINARY_INV)
for (i = 0; i < 768; i++)
// i = src[j] - mean[j] + 255
// i - 255 <= -idelta ? imaxval : 0
// = src[j] - mean[j] + 255 - 255 <= -idelta ? imaxval : 0
// = src[j] <= mean[j] - idelta ? imaxval : 0
tab[i] = (uchar)(i - 255 <= -idelta ? imaxval : 0);
else
CV_Error(CV_StsBadFlag, "Unknown/unsupported threshold type");
// 如果连续,加速运算
if (src.isContinuous() && mean.isContinuous() && dst.isContinuous())
{
size.width *= size.height;
size.height = 1;
}
// 逐像素计算 src[j] - mean[j] + 255,并查表得到结果
for (i = 0; i < size.height; i++)
{
const uchar* sdata = src.data + src.step*i;
const uchar* mdata = mean.data + mean.step*i;
uchar* ddata = dst.data + dst.step*i;
for (j = 0; j < size.width; j++)
// 将 [-255, 255] 映射到 [0, 510] 然后查表
ddata[j] = tab[sdata[j] - mdata[j] + 255];
}
}
ret3, th1 = cv2.threshold(img, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)
大多数计算机视觉任务失败的最重要因素是噪声。噪声可以是高斯噪声(由于不同的光照条件而产生)和椒盐噪声(稀疏的明暗干扰)。
dst = cv2.fastNlMeansDenoisingColored(img, None, 10, 10, 7, 21)
先对原图进行缩放处理,处理成固定的像素面积。 将 RGB 矩阵分离为单独的颜色通道,然后使用 Counter() 函数分别对 3 个 RGB 矩阵中的每个像素值进行频率计数。
然后,选择 10 个出现频率最高的值并取它们的平均值来获得结果像素值。
最后,只需使用 np.zeros() 生成一个空白图像,并用获得的背景色填充它即可显示最终结果。 这种技术只需 40 行代码就可以产生结果!
对 RGB 值使用 K-Means 聚类算法,并找出图像中存在的一组不同颜色的聚类。 之后,再次利用频率计数,最后找到背景色。 这种方法涉及到无监督机器学习的使用,其应用范围远远超出了背景颜色检测。
图像分割任务大量使用这种方法对图像进行 K 均值聚类。
K-Means 算法试图找到使平凡误差准则函数最小的簇。 当潜在的簇形状是凸面的,簇与簇之间区别较明显,且簇大小相近时,其聚类结果较理想。
前面提到,该算法时间复杂度为 O(tkmn),与样本数量线性相关,所以,对于处理大数据集合,该算法非常高效,且伸缩性较好。 但该算法除了要事先确定簇数 K 和对初始聚类中心敏感外,经常以局部最优结束,同时对“噪声”和孤立点敏感, 并且该方法不适于发现非凸面形状的簇或大小差别很大的簇。
缺点:
这个算法的核心是采用深度学习标记出前景物体。而模型是直接下载使用的。尴尬。