2015-09-21 3 views
1

Я пытаюсь растянуть гистограмму изображения, используя логарифмическое преобразование. В основном, я применяю операцию log к интенсивности каждого пикселя. Когда я пытаюсь изменить значение изображения в каждом пикселе, новые значения не сохраняются, но гистограмма выглядит нормально. Кроме того, максимальное значение неверно. Это мой код:OpenCV/python: Как изменить значения пикселей пикселей с помощью формулы?

import cv2 
import numpy as np 
import math 
from matplotlib import pyplot as plt 

img = cv2.imread('messi.jpg',0) 
img2 = img 
for i in range(0,img2.shape[0]-1): 
    for j in range(0,img2.shape[1]-1): 
     if (math.log(1+img2[i,j],2)) < 0: 
      img2[i,j]=0 
     else: 
      img2[i,j] = np.int(math.log(1+img2[i,j],2)) 
      print (np.int(math.log(1+img2[i,j],2))) 

print (img2.ravel().max())   
cv2.imshow('LSP',img2) 
cv2.waitKey(0) 
fig = plt.gcf() 
fig.canvas.set_window_title('LSP histogram') 
plt.hist(img2.ravel(),256,[0,256]); plt.show() 
img3 = img2 
B = np.int(img3.max()) 
A = np.int(img3.min()) 
print ("Maximum intensity = ", B) 
print ("minimum intensity = ", A) 

Это также гистограмма я получаю:

This is the resulted histogram

Однако максимальная интенсивность показывает 186! Это вообще не применяется к правильной логарифмической операции.

Любые идеи?

+1

@Miki img3 = img2 – zinon

ответ

6

Код, который вы написали, выполняет логарифмическое преобразование, применяемое к интенсивностям изображения. Причина, по которой вы получаете такую ​​высокую паразитную интенсивность, как максимум, потому что ваши петли for ошибочны. В частности, ваш range неверен. range является эксклюзивный периода окончания, что означает, что вы должны пойти до img.shape[0] и img.shape[1] соответственно, а не img.shape[0]-1 или img.shape[1]-1. Поэтому вам не хватает последней строки и последнего столбца изображения, и они не затрагиваются логарифмической операцией. Максимум, о котором сообщается, относится к одному из этих пикселей в последней строке или столбце, которые вы не касались.

После того, как вы это исправить, вы не получите эти плохие интенсивности больше:

for i in range(0,img2.shape[0]): # Change 
    for j in range(0,img2.shape[1]): # Change 
     if (math.log(1+img2[i,j],2)) < 0: 
      img2[i,j]=0 
     else: 
      img2[i,j] = np.int(math.log(1+img2[i,j],2)) 

Doing что теперь дает нам:

('Maximum intensity = ', 7) 
('minimum intensity = ', 0) 

Однако то, что вы собираетесь получить сейчас очень темное изображение. Гистограмма, которую вы показали нам, иллюстрирует, что все пиксели изображения находятся в темном диапазоне ... примерно между [0-7]. Из-за этого большая часть вашего изображения будет темной, если вы используете uint8 в качестве типа данных для визуализации. Примите к сведению, что я искал для изображения Лионель Месси, который является частью из OpenCV учебники, и это изображение, которое я нашел:

Источник: https://opencv-python-tutroals.readthedocs.org/en/latest/_images/roi.jpg

Ваш код преобразования это в оттенках серого , и это хорошо для вашего вопроса. Теперь, используя вышеупомянутое изображение, если вы на самом деле показать, что граф гистограммы выглядит так же, как то, что Интенсивности в бункер в гистограмме, это то, что мы получаем для img2:

In [41]: np.unique(img2) 
Out[41]: array([0, 1, 2, 3, 4, 5, 6, 7], dtype=uint8) 

In [42]: np.bincount(img2.ravel()) 
Out[42]: array([ 86, 88, 394, 3159, 14841, 29765, 58012, 19655]) 

Как вы можете видеть, основная часть пикселей изображения колеблется между диапазоном [0-7], поэтому все выглядит черным.Если вы хотите увидеть это лучше, возможно масштабировать изображение примерно 255/7 = 36 или таким образом, мы можем видеть изображение лучше:

img2 = 36*img2 
cv2.imshow('LSP',img2) 
cv2.waitKey(0) 

Мы получаем этот образ:

enter image description here

Я также получить эту гистограмму :

enter image description here

Это лично выглядит очень некрасиво ... по крайней мере, для меня. Таким образом, я бы рекомендовал вам выбрать более значимое преобразование изображения, если вы хотите растянуть гистограмму. Фактически операция logсжимает динамический диапазон гистограммы. Если вы хотите растянуть гистограмму, пройдите противоположным способом и попробуйте операцию степеней. В частности, с учетом интенсивности входного сигнала и выходной сигнал определяется как:

out = c*in^(p) 

in является интенсивностью входного сигнала, p является силой и c является константой для того, чтобы масштабировать изображение таким образом, что максимальная интенсивность получает отображается на та же максимальная интенсивность ввода, когда вы закончите, и ничего больше. Это может быть сделано путем вычисления c так, что:

c = (img2.max())/(img2.max()**p) 

... где p сила вы хотите. Кроме того, преобразование с помощью степенного закона можно объяснить с этой хорошей диаграммой:

Источник: http://www.nptel.ac.in/courses/117104069/chapter_8/8_14.html

В принципе, полномочия, которые меньше, чем 1 выполнить разложение интенсивности где более темные интенсивности получить толчок к более светлой стороне. Аналогично, мощности, которые больше 1, выполняют сжатие интенсивности, когда более легкие интенсивности попадают в более темную сторону. В вашем случае вы хотите развернуть гистограмму, и поэтому вы хотите первый вариант. В частности, попробуйте сделать меньшие интенсивности, направленные на более широкий диапазон. Это можно сделать, выбирая мощность, которая меньше 1 ... например, попробуйте 0,5.

Вы хотите изменить свой код так, чтобы это так:

img2 = img2.astype(np.float) # Cast to float 
c = (img2.max())/(img2.max()**(0.5)) 
for i in range(0,img2.shape[0]-1): 
    for j in range(0,img2.shape[1]-1): 
     img2[i,j] = np.int(c*img2[i,j]**(0.5)) 

# Cast back to uint8 for display 
img2 = img2.astype(np.uint8) 

Делая это, я получаю это изображение:

enter image description here

Я также получаю эту гистограмму:

enter image description here


Minor Примечание

Если я могу предложить что-то с точки зрения эффективности, я бы не рекомендовал вам цикл по всему изображению и установите каждый пиксель индивидуально ... вот как numpy массивы были не должны быть используемый. Вы можете добиться того, что вы хотите использовать в одной строке кода.

С вашим старым кодом, используйте np.log2, не math.log с основанием 2 с numpy массивами:

import cv2 
import numpy as np 
from matplotlib import pyplot as plt 

# Your code 
img = cv2.imread('messi.jpg',0) 

# New code 
img2 = np.log2(1 + img.astype(np.float)).astype(np.uint8) 

# Back to your code 
img2 = 36*img2 # Edit from before 
cv2.imshow('LSP',img2) 
cv2.waitKey(0) 
fig = plt.gcf() 
fig.canvas.set_window_title('LSP histogram') 
plt.hist(img2.ravel(),256,[0,256]); plt.show() 
img3 = img2 
B = np.int(img3.max()) 
A = np.int(img3.min()) 
print ("Maximum intensity = ", B) 
print ("minimum intensity = ", A) 

cv2.destroyAllWindows() # Don't forget this 

Точно так же, если вы хотите применить преобразование степенного, это очень просто:

import cv2 
import numpy as np 
from matplotlib import pyplot as plt 

# Your code 
img = cv2.imread('messi.jpg',0) 

# New code 
c = (img2.max())/(img2.max()**(0.5)) 
img2 = (c*img.astype(np.float)**(0.5)).astype(np.uint8) 

#... rest of code as before 
+0

Отличный и полный ответ !! Большое спасибо!!! У меня есть еще один вопрос. В случае, если вы хотите выполнить уравнение '(255 * (img2-A))/(B-A)' для увеличения интенсивностей до границ 0-255, я получаю вместо этого интенсивности 0-36. Можете ли вы помочь мне исправить это? – zinon

+0

@zinon - Тебе очень рады. Что касается этой небольшой ошибки, я не уверен, почему это происходит. Это произойдет, только если вы сделали (img2 - A)/(B - A) '. Вы уверены, что это то, что вы получаете? Можете ли вы обновить свой пост и код, чтобы показать мне, что вы делаете? – rayryeng

+0

Да, я уверен. Мне нужно преобразовать 255 или A или B в другой тип? – zinon

Смежные вопросы