【问题标题】:I want to apply a threshold to pixels in image using python. Where did I make a mistake?我想使用 python 对图像中的像素应用阈值。我在哪里做错了?
【发布时间】:2018-12-12 01:07:31
【问题描述】:

我想生成作为阈值的输出。还有我的错误:

img_thres = n_pix[y, x]
TypeError: 'int' 对象不可下标

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)

【问题讨论】:

  • n_pix 始终为 0。您认为 0[y,x] 是什么意思?

标签: python image image-processing threshold image-thresholding


【解决方案1】:

由于您已经在使用 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 循环快 3300 倍,OpenCV 版本快 27000 倍!!!

您可以通过汇总图像中的差异来检查它们是否产生相同的结果,如下所示:

np.sum(method1(img)-method3(img))
0.0 

开始图片:

结果图片:

【讨论】:

  • 我会赞成任何进行适当基准测试的答案。 :)
  • 你说的太好了。感谢您的帮助和解释:)
  • 我很高兴 - 很高兴它对你有用。请记住,问题和答案都是免费的,所以如果您再次遇到困难,请回来 :-) 祝您的项目好运!
【解决方案2】:

试试这个

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)

【讨论】:

  • 对不起,这是我的错误。我编辑了代码,现在可以正常工作了。谢谢@CrisLuengo。
【解决方案3】:

要将阈值应用于图像,只需执行以下操作:

img_thres = img >= 0.5

您不需要任何循环来进行阈值处理。

如果从您的代码看来,您不想设置阈值,而是将值低于 0.5 的所有像素设置为 0,则可以使用“逻辑索引”阈值产生的二进制图像作为如下:

img_thres = img
img_thres[ img < 0.5 ] = 0

使用 NumPy 矢量化操作的代码总是比显式循环遍历每个数组元素的代码更有效。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-12-15
    • 2015-03-21
    • 2022-01-17
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多