我想使用 python 对图像中的像素应用阈值。我哪里弄错了?
I want to apply a threshold to pixels in image using python. Where did I make a mistake?
我想生成作为阈值的输出。我的错误:
img_thres = n_pix[y, x]
TypeError: 'int' object is not subscriptable
import cv2
import numpy as np
import matplotlib as plt
img = cv2.imread("cicek.png",0)
img_rgb = cv2.imread("cicek.png")
h = img.shape[0]
w = img.shape[1]
img_thres= []
n_pix = 0
# loop over the image, pixel by pixel
for y in range(0, h):
for x in range(0, w):
# threshold the pixel
pixel = img[y, x]
if pixel < 0.5:
n_pix = 0
img_thres = n_pix[y, x]
cv2.imshow("cicek", img_thres)
要对图像应用阈值,只需执行以下操作:
img_thres = img >= 0.5
您不需要任何循环来进行阈值处理。
如果从您的代码看来,您不想设置阈值,而是将值低于 0.5 的所有像素设置为 0,则您可以使用 [=20 的阈值产生的二值图像=]如下:
img_thres = img
img_thres[ img < 0.5 ] = 0
使用 NumPy 向量化运算的代码总是比显式循环遍历每个数组元素的代码更高效。
试试这个
import cv2
import numpy as np
import matplotlib as plt
img = cv2.imread("cicek.png",0)
img_rgb = cv2.imread("cicek.png")
h = img.shape[0]
w = img.shape[1]
img_thres= np.zeros((h,w))
n_pix = 0
# loop over the image, pixel by pixel
for y in range(0, h):
for x in range(0, w):
# threshold the pixel
pixel = img[y, x]
if pixel < 128: # because pixel value will be between 0-255.
n_pix = 0
else:
n_pix = pixel
img_thres[y, x] = n_pix
cv2.imshow("cicek", img_thres)
由于您已经在使用 OpenCV,您不妨使用其优化的 SIMD 代码来进行阈值处理。它不仅更短、更易于维护,而且速度更快。它看起来像这样:
_, thres = cv2.threshold(img,127,255,cv2.THRESH_TOZERO)
是的,就是这样!这将替换您的所有代码。
基准测试和演示
大量借鉴其他答案,我将:
- 一种使用双
for
循环的方法,
- 一个 Numpy 方法,并且
- 我建议的 OpenCV 方法
和运行 IPython中的一些时序测试。所以,我将这段代码保存为 thresh.py
#!/usr/bin/env python3
import cv2
import numpy as np
def method1(img):
"""Double loop over pixels"""
h = img.shape[0]
w = img.shape[1]
img_thres= np.zeros((h,w))
# loop over the image, pixel by pixel
for y in range(0, h):
for x in range(0, w):
# threshold the pixel
pixel = img[y, x]
img_thres[y, x] = 0 if pixel < 128 else pixel
return img_thres
def method2(img):
"""Numpy indexing"""
img_thres = img
img_thres[ img < 128 ] = 0
return img_thres
def method3(img):
"""OpenCV thresholding"""
_, thres = cv2.threshold(img,127,255,cv2.THRESH_TOZERO)
return thres
img = cv2.imread("gradient.png",cv2.IMREAD_GRAYSCALE)
然后,我开始 IPython 并做了:
%load thresh.py
然后,我对三种方法进行了计时:
%timeit method1(img)
81 ms ± 545 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)
%timeit method2(img)
24.5 µs ± 818 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)
%timeit method3(img)
3.03 µs ± 79.5 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
请注意,第一个结果以毫秒为单位,而其他两个以微秒为单位。 Numpy 版本比 for 循环快 3,300 倍,OpenCV 版本快 27,000 倍!!!
您可以通过像这样计算图像中的差异来检查它们产生相同的结果:
np.sum(method1(img)-method3(img))
0.0
起始图片:
结果图片:
我想生成作为阈值的输出。我的错误:
img_thres = n_pix[y, x]
TypeError: 'int' object is not subscriptable
import cv2
import numpy as np
import matplotlib as plt
img = cv2.imread("cicek.png",0)
img_rgb = cv2.imread("cicek.png")
h = img.shape[0]
w = img.shape[1]
img_thres= []
n_pix = 0
# loop over the image, pixel by pixel
for y in range(0, h):
for x in range(0, w):
# threshold the pixel
pixel = img[y, x]
if pixel < 0.5:
n_pix = 0
img_thres = n_pix[y, x]
cv2.imshow("cicek", img_thres)
要对图像应用阈值,只需执行以下操作:
img_thres = img >= 0.5
您不需要任何循环来进行阈值处理。
如果从您的代码看来,您不想设置阈值,而是将值低于 0.5 的所有像素设置为 0,则您可以使用 [=20 的阈值产生的二值图像=]如下:
img_thres = img
img_thres[ img < 0.5 ] = 0
使用 NumPy 向量化运算的代码总是比显式循环遍历每个数组元素的代码更高效。
试试这个
import cv2
import numpy as np
import matplotlib as plt
img = cv2.imread("cicek.png",0)
img_rgb = cv2.imread("cicek.png")
h = img.shape[0]
w = img.shape[1]
img_thres= np.zeros((h,w))
n_pix = 0
# loop over the image, pixel by pixel
for y in range(0, h):
for x in range(0, w):
# threshold the pixel
pixel = img[y, x]
if pixel < 128: # because pixel value will be between 0-255.
n_pix = 0
else:
n_pix = pixel
img_thres[y, x] = n_pix
cv2.imshow("cicek", img_thres)
由于您已经在使用 OpenCV,您不妨使用其优化的 SIMD 代码来进行阈值处理。它不仅更短、更易于维护,而且速度更快。它看起来像这样:
_, thres = cv2.threshold(img,127,255,cv2.THRESH_TOZERO)
是的,就是这样!这将替换您的所有代码。
基准测试和演示
大量借鉴其他答案,我将:
- 一种使用双
for
循环的方法, - 一个 Numpy 方法,并且
- 我建议的 OpenCV 方法
和运行 IPython中的一些时序测试。所以,我将这段代码保存为 thresh.py
#!/usr/bin/env python3
import cv2
import numpy as np
def method1(img):
"""Double loop over pixels"""
h = img.shape[0]
w = img.shape[1]
img_thres= np.zeros((h,w))
# loop over the image, pixel by pixel
for y in range(0, h):
for x in range(0, w):
# threshold the pixel
pixel = img[y, x]
img_thres[y, x] = 0 if pixel < 128 else pixel
return img_thres
def method2(img):
"""Numpy indexing"""
img_thres = img
img_thres[ img < 128 ] = 0
return img_thres
def method3(img):
"""OpenCV thresholding"""
_, thres = cv2.threshold(img,127,255,cv2.THRESH_TOZERO)
return thres
img = cv2.imread("gradient.png",cv2.IMREAD_GRAYSCALE)
然后,我开始 IPython 并做了:
%load thresh.py
然后,我对三种方法进行了计时:
%timeit method1(img)
81 ms ± 545 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)
%timeit method2(img)
24.5 µs ± 818 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)
%timeit method3(img)
3.03 µs ± 79.5 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
请注意,第一个结果以毫秒为单位,而其他两个以微秒为单位。 Numpy 版本比 for 循环快 3,300 倍,OpenCV 版本快 27,000 倍!!!
您可以通过像这样计算图像中的差异来检查它们产生相同的结果:
np.sum(method1(img)-method3(img))
0.0
起始图片:
结果图片: