Я хочу применить порог к пикселям в изображении, используя Python.Где я ошибся? - PullRequest
0 голосов
/ 10 декабря 2018

Я хочу создать вывод, который является порогом.И моя ошибка:

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)

Ответы [ 3 ]

0 голосов
/ 11 декабря 2018

Попробуйте это

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)
0 голосов
/ 11 декабря 2018

Поскольку вы уже используете OpenCV , вы также можете использовать его оптимизированный код SIMD для выполнения установки порога.Он не только короче и проще в обслуживании, но и намного быстрее.Это выглядит так:

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

Да, все!Это заменяет весь ваш код.


Тестирование и демонстрация

Заимствуя из других ответов, я собрал:

  • aметод с использованием двойных 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 в 3300 раз быстрее, чем циклы for, и что версия OpenCV в 27000 раз быстрее !!!

Вы можете проверить, что они дают одинаковый результат, суммируя различия в изображениях, как показано ниже:

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

Начальное изображение:

enter image description here

Изображение результата:

enter image description here

0 голосов
/ 11 декабря 2018

Чтобы применить порог к изображению, просто сделайте это:

img_thres = img >= 0.5

Вам не нужны циклы для порогового значения.

Если, как видно из вашего кода, вы не используетене хотите порогового значения, но вместо этого установите все пиксели со значением ниже 0,5 на 0, вы можете использовать двоичное изображение, которое получается из порога для «логического индексирования», следующим образом:

img_thres = img
img_thres[ img < 0.5 ] = 0

Код, который используетвекторизованные операции NumPy всегда более эффективны, чем код, который явно зацикливается на каждом элементе массива.

...