【问题标题】:How to group and highlight group of pixels in an image using OpenCV? [closed]如何使用 OpenCV 对图像中的像素组进行分组和突出显示? [关闭]
【发布时间】:2020-03-04 21:14:58
【问题描述】:

在对图像进行错误级别分析的过程中,我想使用 OpenCV 突出显示像素变化(仅使用单个图像而不是差异)。我知道输出图像的像素级值,但不确定将它们组合在一起并为其分配形状的方法(下面的示例,其中使用形状指定了像素更改)。我想知道是否可以检测到具有较亮像素的圆圈并将它们分组并为像素添加分组形状

输入图像:

结果图片:

【问题讨论】:

  • the methods to group them together and assign a shape to that(Example below where the pixel change is specified with a shape). 是什么意思?如果您在示例中对像素更改结果进行“分组”并分配一个形状,您应该得到一个弧形或圆形;但你的结果是一个边界框
  • 矩形只是一个例子,是的,我如何对像素变化进行分组?
  • 要对靠近的点进行分组,您可以使用聚类方法(如 k-means 或凝聚),或者在这种情况下,您可以使用足够大的内核进行扩张以获得一个包含所有的点。取决于您的用例。
  • 你能提供任何代码示例吗?
  • 您可以对图像进行阈值处理并使用 findContours 对连接的检测到的像素进行“分组”

标签: python image opencv image-processing image-segmentation


【解决方案1】:

如果我理解正确,您想在新图像中突出输入和输出图像之间的差异。为此,您可以使用Image Quality Assessment: From Error Visibility to Structural Similarity 中引入的结构相似性指数 (SSIM) 采用定量方法来确定图像之间的确切差异。此方法已在 scikit-image 库中实现,用于图像处理。您可以使用pip install scikit-image 安装scikit-image

skimage.measure.compare_ssim() 函数返回一个score 和一个diff 图像。 score 表示两个输入图像之间的结构相似性指数,可以落在范围 [-1,1] 之间,值越接近表示相似性越高。但是由于您只对这两个图像的不同之处感兴趣,因此我们将重点关注diff 图像。具体来说,diff 图像包含实际图像差异,较暗区域具有更多差异。较大的差异区域以黑色突出显示,而较小的差异以灰色突出。这是diff 图片

如果您仔细观察,可能会出现由.jpg 有损压缩造成的灰色噪声区域。因此,为了获得更清晰的结果,我们执行形态学操作来平滑图像。如果图像使用无损图像压缩格式,例如.png,我们将获得更清晰的结果。清理图像后,我们用绿色突出显示差异

from skimage.measure import compare_ssim
import numpy as np
import cv2

# Load images and convert to grayscale
image1 = cv2.imread('1.jpg')
image2 = cv2.imread('2.jpg')
image1_gray = cv2.cvtColor(image1, cv2.COLOR_BGR2GRAY)
image2_gray = cv2.cvtColor(image2, cv2.COLOR_BGR2GRAY)

# Compute SSIM between two images
(score, diff) = compare_ssim(image1_gray, image2_gray, full=True)

# The diff image contains the actual image differences between the two images
# and is represented as a floating point data type in the range [0,1] 
# so we must convert the array to 8-bit unsigned integers in the range
# [0,255] before we can use it with OpenCV
diff = 255 - (diff * 255).astype("uint8")

cv2.imwrite('original_diff.png',diff)

# Perform morphological operations
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (3,3))
opening = cv2.morphologyEx(diff, cv2.MORPH_OPEN, kernel, iterations=1)
close = cv2.morphologyEx(opening, cv2.MORPH_CLOSE, kernel, iterations=1)
diff = cv2.merge([close,close,close])

# Color difference pixels
diff[np.where((diff > [10,10,50]).all(axis=2))] = [36,255,12]

cv2.imwrite('diff.png',diff)

【讨论】:

  • 或者,您可以获取差异区域的外轮廓并绘制它,这样您就不会用颜色覆盖差异。这样您就可以突出显示它们的位置,但要保持它们可见。
  • 感谢您的解释,但实际上我想在给定的单个图像中获取不均匀的密集像素,然后绘制一个显示不均匀密集像素的形状,就像您在问题中的输入图像中看到的一样有一个与其他像素不同的圆圈,该区域应该以任何形状突出显示。
【解决方案2】:

我认为最好的方法是简单地对图像进行阈值化并应用形态变换。

我得到了以下结果。

阈值 + 形态学:

选择最大的组件:

使用此代码:

cv::Mat result;
cv::Mat img = cv::imread("fOTmh.jpg");

//-- gray & smooth image
cv::cvtColor(img, result, cv::COLOR_BGR2GRAY);
cv::blur(result, result, cv::Size(5,5));

//-- threashold with max value of the image and smooth again!
double min, max;
cv::minMaxLoc(result, &min, &max);
cv::threshold(result, result, 0.3*max, 255, cv::THRESH_BINARY);
cv::medianBlur(result, result, 7);

//-- apply Morphological Transformations
cv::Mat se = getStructuringElement(cv::MORPH_ELLIPSE, cv::Size(11, 11));
cv::morphologyEx(result, result, cv::MORPH_DILATE, se);
cv::morphologyEx(result, result, cv::MORPH_CLOSE, se);

//-- find the largest component
vector<vector<cv::Point> > contours;
vector<cv::Vec4i> hierarchy;
cv::findContours(result, contours, hierarchy, cv::RETR_LIST, cv::CHAIN_APPROX_NONE);
vector<cv::Point> *l = nullptr;
for(auto &&c: contours){
    if (l==nullptr || l->size()< c.size())
        l = &c;
}

//-- expand and plot Rect around the largest component
cv::Rect r = boundingRect(*l);
r.x -=10;
r.y -=10;
r.width +=20;
r.height +=20;
cv::rectangle(img, r, cv::Scalar::all(255), 3);


//-- result
cv::resize(img, img, cv::Size(), 0.25, 0.25);
cv::imshow("result", img);

Python 代码:

import cv2 as cv

img = cv.imread("ELA_Final.jpg")

result = cv.cvtColor(img, cv.COLOR_BGR2GRAY);
result = cv.blur(result, (5,5));

minVal, maxVal, minLoc, maxLoc = cv.minMaxLoc(result)
ret,result = cv.threshold(result, 0.3*maxVal, 255, cv.THRESH_BINARY)
median = cv.medianBlur(result, 7)

se = cv.getStructuringElement(cv.MORPH_ELLIPSE,(11, 11));
result = cv.morphologyEx(result, cv.MORPH_DILATE, se);
result = cv.morphologyEx(result, cv.MORPH_CLOSE, se);

_,contours, hierarchy = cv.findContours(result,cv.RETR_LIST, cv.CHAIN_APPROX_NONE)

x = []

for eachCOntor in contours:
    x.append(len(eachCOntor))
m = max(x)
p = [i for i, j in enumerate(x) if j == m]

color = (255, 0, 0) 
x, y, w, h = cv.boundingRect(contours[p[0]])
x -=10
y -=10
w +=20
h +=20
cv.rectangle(img, (x,y),(x+w,y+h),color, 3)

img =  cv.resize( img,( 1500, 700), interpolation = cv.INTER_AREA)
cv.imshow("result", img)
cv.waitKey(0)

【讨论】:

  • 能否请您发布一个相同的python替代品
  • 谢谢,我用 python 重写了代码并且能够得到我想要的,但仍然有一个问题,为什么应该选择最大的 contours 以及是什么让数组更长?
  • 最大的组件是收集最大错误并通过阈值显示的区域。数组包含白色像素位置。
  • @SundeepPidugu 如果这回答了您的问题,请将其标记为答案。否则请告诉我是否可以帮助您。
猜你喜欢
  • 1970-01-01
  • 2012-07-15
  • 1970-01-01
  • 1970-01-01
  • 2019-06-15
  • 2020-08-28
  • 2020-10-28
  • 2013-11-13
  • 2012-02-09
相关资源
最近更新 更多