I want to apply a threshold to pixels in image using python. Where did I make a mistake?

我的未来我决定 提交于 2019-12-11 07:50:43

问题


I want to generate the output that is a threshold. And my error:

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)

回答1:


As you are already using OpenCV, you may as well use its optimised SIMD code to do your thresholding. Not only is it shorter and easier to maintain, it is also miles faster. It looks like this:

_, thres = cv2.threshold(img,127,255,cv2.THRESH_TOZERO)

Yes, that's it! That replaces all your code.


Benchmarking and demo

Borrowing heavily from other answers, I put together:

  • a method using double for loops,
  • a Numpy method, and
  • the OpenCV method I am suggesting

and ran some timing tests inside IPython. So, I saved this code as 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)

Then, I started IPython and did:

%load thresh.py

Then, I timed the three methods:

%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)

Note that the first result is in milliseconds whereas the other two are in microseconds. The Numpy version is 3,300 times faster than the for loops, and that the OpenCV version is 27,000 times faster!!!

You can check they produce the same result by totting up the differences in the images like this:

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

Start image:

Result image:




回答2:


Try this

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)



回答3:


To apply a threshold to an image just do this:

img_thres = img >= 0.5

You don't need any loops for thresholding.

If, as it seems from your code, you don't want to threshold, but instead set all pixels with a value below 0.5 to 0, you can use the binary image that results from a threshold for "logical indexing" as follows:

img_thres = img
img_thres[ img < 0.5 ] = 0

Code that uses the NumPy vectorized operations is always more efficient that code that explicitly loops over each array element.



来源:https://stackoverflow.com/questions/53712937/i-want-to-apply-a-threshold-to-pixels-in-image-using-python-where-did-i-make-a

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!