Неожиданный вывод Opencv для оператора Sobel

Я извлекаю белые полосы из этого изображения, но заинтригован, чтобы увидеть вывод основного оператора Собеля в изображении «Лаборатория». Хотя я рад видеть черные полосы как желаемый результат, я не могу оправдать то, что происходит за оператором «np.hstack». Я не получаю такой же вывод, если plt.imshow() применяется только к «sobel». Желаемый результат — бинарное изображение, содержащее белые полосы.

введите здесь описание изображения

import numpy as np
import cv2
import os,sys
from matplotlib import pyplot as plt    

def getColorSpaces(image):
    rgb = cv2.cvtColor(image,cv2.COLOR_RGB2BGR)
    gray = cv2.cvtColor(image,cv2.COLOR_RGB2GRAY)        
    return rgb,gray

def getImageDimnesion(image):
    height,width = image.shape[:2]        
    return height,width

def showImage(image,title,cmap):
    plt.imshow(image,cmap=cmap)
    plt.axis('off')
    plt.title(title)


def splitRGBChannels(image):
  red, green, blue= cv2.split(img)      
  return red, green, blue

def getMagnitude(gray):        
    sobelx = cv2.Sobel(gray, cv2.CV_64F, 1, 0, ksize=3)
    sobely = cv2.Sobel(gray, cv2.CV_64F, 0, 1, ksize=3)
    abs_sobelx = np.absolute(sobelx)
    abs_sobely = np.absolute(sobely)        
    magnitude=np.sqrt(abs_sobelx*abs_sobelx+abs_sobely*abs_sobely)        
    return magnitude,np.arctan2(abs_sobely,abs_sobelx)


def applySobel(gray):        
    sobelx = cv2.Sobel(gray, cv2.CV_64F, 1, 0, ksize=3)
    sobely = cv2.Sobel(gray, cv2.CV_64F, 0, 1, ksize=3)
    abs_sobelx = np.absolute(sobelx)
    abs_sobely = np.absolute(sobely)
    return abs_sobelx+abs_sobely


images_path=r'images'
images=os.listdir(images_path)

for im in images[:]:
    print(im)        
    img = cv2.imread(os.path.join(images_path,im))  

    plt.axis('off')
    plt.title('Originial')
    plt.imshow(img,cmap='gray') 
    plt.show()

for im in images[:]:
    print(im)
    plt.figure(figsize=(12, 12))
    img = cv2.imread(os.path.join(images_path,im))    

    hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
    lab=cv2.cvtColor(img, cv2.COLOR_BGR2LAB)
    h,s,v = cv2.split(hsv)
    l,a,b = cv2.split(lab)
    sobel=applySobel(lab)
    imgs_comb = np.hstack([img,lab,sobel])

    plt.axis('off')
    plt.title('Originial-Lab-Sobel')
    plt.imshow(imgs_comb,cmap='gray') 
    plt.show()

ИЗМЕНИТЬ1

plt.axis('off')
plt.title('img')
plt.imshow(img,cmap='gray') 
plt.show()

plt.axis('off')
plt.title('lab')
plt.imshow(lab,cmap='gray') 
plt.show()

plt.axis('off')
plt.title('sobel')
plt.imshow(sobel,cmap='gray') 
plt.show()

введите здесь описание изображения

plt.axis('off')
plt.title('hstack')
plt.imshow(imgs_comb,cmap='gray')  #<<<<<Different output but is generic when tried with different images
plt.show()

введите здесь описание изображения


person addcolor    schedule 17.11.2019    source источник


Ответы (2)


Ваш метод applySobel ожидает изображение в градациях серого (одноканальное) в качестве входных данных, но вы используете lab (3-канальное изображение) в качестве входных данных, которые будут применять фильтрацию Собеля ко всем 3 каналам. Неожиданный результат возникает из-за того, что plt.imshow интерпретирует Lab-каналы, отфильтрованные Собелем, как RGB-каналы вашего изображения.

Он работает так, как задумано, если вместо этого вы используете только l, a или b (или другой метод преобразования Lab в серый). Однако результат не будет бинарным. Чтобы сделать его двоичным, вы можете применить порог (используя cv2.threshold(img, threshold, max_value, cv2.THRESH_BINARY). Вот пример:

import cv2
import numpy as np
from matplotlib import pyplot as plt
from skimage.io import imread


def applySobel(gray):
    sobelx = cv2.Sobel(gray, cv2.CV_64F, 1, 0, ksize=3)
    sobely = cv2.Sobel(gray, cv2.CV_64F, 0, 1, ksize=3)
    abs_sobelx = np.absolute(sobelx)
    abs_sobely = np.absolute(sobely)
    return abs_sobelx + abs_sobely


# Load the image (RGB)
img = imread('https://i.stack.imgur.com/qN2ta.jpg')

# Convert to Lab and split channels
lab = cv2.cvtColor(img, cv2.COLOR_RGB2LAB)
l, a, b = cv2.split(lab)

# Plot image of Lab-channels
plt.title('L, a, and b channel')
plt.imshow(np.hstack([l, a, b]), cmap='gray')
plt.show()

# Apply Sobel to L-channel (the other channels have low contrast)
l_sobel = applySobel(l)

# Plot result
plt.title('Sobel-filtered L-channel')
plt.imshow(l_sobel, cmap='gray')
plt.show()

# Make result binary by applying a threshold
sobel_thresh = np.uint8(cv2.threshold(l_sobel, 500, 255, cv2.THRESH_BINARY)[1])

# Plot binary result
plt.title('Thresholded Sobel-filtered L-channel')
plt.imshow(sobel_thresh, cmap='gray')
plt.show()

В результате получаются следующие изображения:

каналы LAB L-канал, отфильтрованный Sobel Пороговый L-канал, фильтрованный Собелем

Фильтр Собеля используется для обнаружения краев, поэтому он выделяет только края, а не целые полосы. Поэтому, если ваша цель — выделить полосы целиком, прямая пороговая установка L-канала будет более эффективной:

# Directly threshold L-channel and plot
plt.imshow(cv2.threshold(l, 220, 255, cv2.THRESH_BINARY)[1], cmap='gray')
plt.show()

Результат:

введите здесь описание изображения

Также обратите внимание, что вы не можете напрямую использовать np.hstack для объединения 3-канальных изображений с изображениями в градациях серого/двоичными изображениями из-за разных размеров. Сначала используйте np.stack((img,) * 3, axis=-1) для преобразования одноканальных изображений в трехканальные изображения.

person Jonathan Feenstra    schedule 19.11.2019
comment
Спасибо за решение этой проблемы. Я думаю, что моя главная ошибка - неправильное использование np.stack() - person addcolor; 21.11.2019
comment
Заметил несколько отличий. Я использую функцию cv2.imread() для чтения изображений. По умолчанию изображение находится в формате BGR. Отредактировал мой запрос, пожалуйста, проверьте. - person addcolor; 21.11.2019
comment
plt.imshow ожидает, что его вход будет в формате RGB. Преобразование из BGR в RGB и наоборот так же просто, как изменение 3-й оси вашего массива numpy: rgb_img = bgr_img[:, :, ::-1]. Вы также можете использовать rgb_img = cv2.cvtColor(bgr_img, cv2.COLOR_BGR2RGB), если хотите, для лучшей читабельности. - person Jonathan Feenstra; 21.11.2019

  • Функция np.hstack не изменяет ваши данные, но изменяет способ отображения изображений. Если вы объедините изображения из разных диапазонов в один массив, функция imshow автоматически масштабируется до максимального диапазона. Вот почему у вас есть разница, когда вы отображаете только одно или несколько изображений.
  • The Sobel function that you designed is proper but:
    • It will be applied to all channels of your lab array. Maybe you would rather like to apply it only on the l channel. But if you check separately the range of l, a and b, you will notice that the intensity there is quite different.
    • Когда вы отображаете результат sobel, imshow автоматически предполагает, что 3 канала, которые вы даете, являются данными RGB, поэтому у вас есть это странное изображение.
    • Если вы просто отобразите plt.imshow(sobel[:, :, 0]), вы получите результаты фильтра Собеля, то есть контуры.
    • Если вы стремитесь получить полосы, а не контуры, вам, вероятно, придется использовать в основном интенсивность, а не контуры.
  • Я бы посоветовал вам взглянуть на алгоритмы github для обнаружения полос глубокого обучения, такие алгоритмы могут превзойти то, что вы можете сделать с помощью простых операторов. Часто репозитории совместно используют модели, и запустить модель несложно.
person 87VN0    schedule 19.11.2019