繁体   English   中英

OpenCV / python:如何使用公式更改图像像素的值?

[英]OpenCV/python: How to change image pixels' values using a formula?

我正在尝试使用对数变换来拉伸图像的直方图。 基本上,我正在对每个像素的强度应用log操作。 当我尝试更改每个像素中的图像值时,不会保存新值,但直方图看起来没问题。 此外,最大值不正确。 这是我的代码:

import cv2
import numpy as np
import math
from matplotlib import pyplot as plt

img = cv2.imread('messi.jpg',0)
img2 = img
for i in range(0,img2.shape[0]-1):
    for j in range(0,img2.shape[1]-1):
        if (math.log(1+img2[i,j],2)) < 0:
            img2[i,j]=0
        else:
            img2[i,j] = np.int(math.log(1+img2[i,j],2))
            print (np.int(math.log(1+img2[i,j],2)))

print (img2.ravel().max())          
cv2.imshow('LSP',img2)
cv2.waitKey(0)
fig = plt.gcf()
fig.canvas.set_window_title('LSP histogram')
plt.hist(img2.ravel(),256,[0,256]); plt.show()
img3 = img2
B = np.int(img3.max())
A = np.int(img3.min())
print ("Maximum intensity = ", B)
print ("minimum intensity = ", A)

这也是我得到的直方图:

这是结果直方图

但是,最大强度显示186! 这根本没有应用适当的对数运算。

有任何想法吗?

您编写的代码执行应用于图像强度的对数变换。 你之所以得到如此高的杂散强度是因为你的for循环是错误的。 具体来说,您的range不正确。 range 包括结束间隔,这意味着你必须分别去img.shape[0]img.shape[1] ,而不是img.shape[0]-1img.shape[1]-1 因此,您缺少图像的最后一行和最后一列,并且这些不会被对数操作触及。 报告的最大值来自您未触摸的最后一行或列中的其中一个像素。

一旦你纠正了这个,你就不再那么强烈了:

for i in range(0,img2.shape[0]): # Change
    for j in range(0,img2.shape[1]): # Change
        if (math.log(1+img2[i,j],2)) < 0:
            img2[i,j]=0
        else:
            img2[i,j] = np.int(math.log(1+img2[i,j],2))

这样做现在给了我们:

('Maximum intensity = ', 7)
('minimum intensity = ', 0)

然而,你现在要得到的是一个非常黑暗的图像。 您向我们展示的直方图说明所有图像像素都在黑暗范围内......大致在[0-7]之间。 因此,如果使用uint8作为可视化的数据类型,则大部分图像将会变暗。 请注意,我搜索了Lionel Messi图像,它是OpenCV教程的一部分,这是我发现的图像:

资料来源: https//opencv-python-tutroals.readthedocs.org/en/latest/_images/roi.jpg

您的代码将其转换为灰度,这对于您的问题来说没问题。 现在,使用上面的图像,如果你实际显示直方图计数的样子以及直方图中每个bin的强度,这就是我们得到的img2

In [41]: np.unique(img2)
Out[41]: array([0, 1, 2, 3, 4, 5, 6, 7], dtype=uint8)

In [42]: np.bincount(img2.ravel())
Out[42]: array([   86,    88,   394,  3159, 14841, 29765, 58012, 19655])

如您所见,大部分图像像素都在[0-7]范围之间徘徊,这就是为什么一切看起来都是黑色的原因。 如果你想更好地看到这一点,或许可以将图像缩放大约255 / 7 = 36左右,我们可以更好地看到图像:

img2 = 36*img2
cv2.imshow('LSP',img2)
cv2.waitKey(0)

我们得到这个图片:

在此输入图像描述

我也得到这个直方图:

在此输入图像描述

个人看起来非常丑陋......至少对我而言。 因此,如果您想要拉伸直方图,我建议您选择更有意义的图像转换。 实际上, log操作压缩直方图的动态范围。 如果要拉伸直方图,请采用相反的方法并尝试幂律运算。 具体来说,给定输入强度,输出定义为:

out = c*in^(p)

in是输入强度, p是幂, c是常数,以确保缩放图像,以便在完成时将最大强度映射到输入的相同最大强度,而不是更大。 这可以通过计算c来完成,这样:

c = (img2.max()) / (img2.max()**p)

......其中p是你想要的力量。 此外,通过幂律的转换可以用这个漂亮的图解释:

资料来源: http//www.nptel.ac.in/courses/117104069/chapter_8/8_14.html

基本上,小于1的功率执行强度扩展,其中较暗的强度被推向较轻的一侧。 类似地,大于1的功率执行强度压缩,其中较轻的强度被推到较暗的一侧。 在您的情况下,您想要扩展直方图,因此您需要第一个选项。 具体来说,尝试使较小的强度朝向更大的范围。 这可以通过选择小于1的功率来完成...例如尝试0.5。

你修改你的代码,使它像这样:

img2 = img2.astype(np.float) # Cast to float
c = (img2.max()) / (img2.max()**(0.5))
for i in range(0,img2.shape[0]-1):
    for j in range(0,img2.shape[1]-1):
        img2[i,j] = np.int(c*img2[i,j]**(0.5))

# Cast back to uint8 for display
img2 = img2.astype(np.uint8)

这样做,我得到这个图像:

在此输入图像描述

我也得到这个直方图:

在此输入图像描述


次要说明

如果我可以在效率方面提出建议,我不建议你遍历整个图像并单独设置每个像素......这就是应该使用numpy数组的方式。 您可以在一行代码中实现所需的矢量化。

使用旧代码,使用np.log2 ,而不是带有numpy数组的base 2的math.log

import cv2
import numpy as np
from matplotlib import pyplot as plt

# Your code
img = cv2.imread('messi.jpg',0)

# New code
img2 = np.log2(1 + img.astype(np.float)).astype(np.uint8)

# Back to your code
img2 = 36*img2 # Edit from before
cv2.imshow('LSP',img2)
cv2.waitKey(0)
fig = plt.gcf()
fig.canvas.set_window_title('LSP histogram')
plt.hist(img2.ravel(),256,[0,256]); plt.show()
img3 = img2
B = np.int(img3.max())
A = np.int(img3.min())
print ("Maximum intensity = ", B)
print ("minimum intensity = ", A)

cv2.destroyAllWindows() # Don't forget this

同样,如果你想应用幂律变换,那很简单:

import cv2
import numpy as np
from matplotlib import pyplot as plt

# Your code
img = cv2.imread('messi.jpg',0)

# New code
c = (img2.max()) / (img2.max()**(0.5))
img2 = (c*img.astype(np.float)**(0.5)).astype(np.uint8)

#... rest of code as before

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM