Commit 7be3eb6e authored by David GEISSBUHLER's avatar David GEISSBUHLER

python version of tan_specular_highlights removed.

parent 87134851
......@@ -5,8 +5,6 @@ from .galbally_iqm_features import compute_quality_features
from .msu_iqa_features import compute_msu_iqa_features
from ._library import remove_highlights
from . import tan_specular_highlights as tsh
def get_config():
"""
......
......@@ -10,12 +10,10 @@ import bob.ip.base
import bob.ip.color
from . import galbally_iqm_features as iqm
#from . import tan_specular_highlights as tsh
from ._library import remove_highlights
''' Utility functions '''
def matlab_rgb2hsv(rgbImage):
# first normalize the range of values to 0-1
......
......@@ -5,6 +5,8 @@
Created on 28 Jun 2017
@author: dgeissbuhler
Compute average specular histogram of an entire picture folder.
'''
from __future__ import print_function
......@@ -13,21 +15,15 @@ import sys
import argparse
import time
import bob.io.base
import bob.io.image
import bob.io.video
import bob.ip.base
import numpy as np
from bob.ip.qualitymeasure import remove_highlights_orig
from bob.ip.qualitymeasure import remove_highlights
from bob.ip.qualitymeasure import tsh
def main(command_line_parameters=None):
"""Remove the specular component of the input image and write result to
a file.
"""
argParser = argparse.ArgumentParser(
description=__doc__,
......@@ -44,17 +40,15 @@ def main(command_line_parameters=None):
'--output',
dest='output',
default=None,
help='output file.')
help='output text file.')
args = argParser.parse_args(command_line_parameters)
num_hist = 0.0
hist_v0 = np.zeros(256, dtype='uint64')
hist_v1 = np.zeros(256, dtype='uint64')
hist_v2 = np.zeros(256, dtype='uint64')
hist = np.zeros(256, dtype='uint64')
f = open(args.output, 'w')
print('# i v0 v1 v2', file=f)
print('# i bin_value', file=f)
# 1. open input image
print("Opening dir: %s" % args.path)
......@@ -63,35 +57,24 @@ def main(command_line_parameters=None):
# 2. compute
for file in files:
print('processing file: %s' % file)
video = bob.io.video.reader(args.path + file)
frame = video[0]
sfi, diff, residue = tsh.remove_highlights(frame.astype(np.float32), 0.06)
residue[np.where(np.isinf(residue))] = 0
residue[np.where(np.isnan(residue))] = 0
residue[np.where(residue < 0)] = 0
residue[np.where(residue > 255)] = 255
hist_v0 = hist_v0 + bob.ip.base.histogram(residue[0], (0.0, 255.0), 256)
sfi, diff, residue = remove_highlights(frame.astype(np.float32), 0.06)
sfi, diff, residue = remove_highlights_orig(frame.astype(np.float32), 0.06)
residue[np.where(np.isinf(residue))] = 0
residue[np.where(np.isnan(residue))] = 0
residue[np.where(residue < 0)] = 0
residue[np.where(residue > 255)] = 255
hist_v1 = hist_v1 + bob.ip.base.histogram(residue[0], (0.0, 255.0), 256)
sfi, diff, residue = remove_highlights(frame.astype(np.float32), 0.06)
residue[np.where(np.isinf(residue))] = 0
residue[np.where(np.isnan(residue))] = 0
residue[np.where(residue < 0)] = 0
residue[np.where(residue > 255)] = 255
hist_v2 = hist_v2 + bob.ip.base.histogram(residue[0], (0.0, 255.0), 256)
hist = hist + bob.ip.base.histogram(residue[0], (0.0, 255.0), 256)
# 1. save output image
for i in range(256):
print(i, hist_v0[i], hist_v1[i], hist_v2[i], file= f)
print(i, hist[i], file= f)
......
......@@ -15,9 +15,7 @@ import bob.io.base
import bob.io.image
import numpy as np
from bob.ip.qualitymeasure import remove_highlights_orig
from bob.ip.qualitymeasure import remove_highlights
from bob.ip.qualitymeasure import tsh
def main(command_line_parameters=None):
"""Remove the specular component of the input image and write result to
......@@ -55,13 +53,6 @@ def main(command_line_parameters=None):
default=0.5,
help='value of epsilon parameter.')
argParser.add_argument(
'-a',
'--algorithm',
dest='algorithm',
default=0,
help='version of the algoritm used.')
args = argParser.parse_args(command_line_parameters)
if not args.inpImg:
......@@ -76,15 +67,7 @@ def main(command_line_parameters=None):
# 2. compute
print("Extracting diffuse component...")
if int(args.algorithm) == 0:
print('v0')
sfi, diff, residue = tsh.remove_highlights(img.astype(np.float32), float(args.epsilon))
elif int(args.algorithm) == 1:
print('v1')
sfi, diff, residue = remove_highlights_orig(img.astype(np.float32), float(args.epsilon))
else:
print('v2')
sfi, diff, residue = remove_highlights(img.astype(np.float32), float(args.epsilon))
sfi, diff, residue = remove_highlights(img.astype(np.float32), float(args.epsilon))
# 1. save output image
print("Saving output file: %s" % args.outImg)
......
'''
Created on May 9, 2016
@author: sbhatta
#------------------------------#
reference:
"separating reflection components of textured surfaces using a single image"
by Robby T. Tan, Katsushi Ikeuchi,
IEEE Transactions on Pattern Analysis and Machine Intelligence (PAMI),
27(2), pp.179-193, February, 2005
This Python implementation is inspired by the C++ code provided by Prof.
Robby Tan:
http://tanrobby.github.io/code.html#
http://tanrobby.github.io/code/highlight.zip
The main difference between this implementation and the original C++
implementation is that here the init_labels() function also ignores pixels
marked G_DIFFUSE. This leads to a smaller number of iterations per epsilon
value, while producing the same result as the C++ code.
#------------------------------#
'''
import numpy as np
# np.seterr(divide='ignore', invalid='ignore')
import bob.io.image
import bob.io.base
# special-pixel-markers. The values don't matter, but they should all
# remain different from each other.
G_SPECULARX = 10
G_SPECULARY = 11
G_DIFFUSE = 12
G_BOUNDARY = 13
G_NOISE = 14
G_CAMERA_DARK = 15
'''
'''
def remove_highlights(srcImage, startEps=0.5, verboseFlag=True):
"""Returns the separate reflection components (highlights and diffuse
components) comprising the input color RGB image. This is the main function
that processes the input srcImage and returns the separate components.
Args:
srcImage: numpy array of shape (3, maxY, maxX), containing a RGB image.
(maxY, maxX) give the image-size (num. rows, num. cols).
startEps: floating point (small value), determines the number of
iterations of algorithm. epsilon is initialized to this
value. At each iteration epsilon is reduced by 0.01, and if
it is not less than 0.0, another iteration is performed.
Thus, a value of 0.5 leads to 50 iterations. Specify a
smaller value if less iterations are desired.
verboseFlag: flag to indicate whether to print some intermediate values
or not. Specify 'False' if you want no message printed.
Outputs:
sfi: numpy array of shape (3, maxY, maxX), containing speckle-free
image
diffuse: numpy array of shape (3, maxY, maxX), containing the diffuse
component
speckleResidue: numpy array of shape (3, maxY, maxX), containing
specular component.
"""
# initialize resulting diffuse-image
diffuse = np.copy(srcImage) # this copy will be updated in zIteration()
srcPixelStatus, sfi, srcMaxChroma, srcMax, srcTotal = specular_free_image(
diffuse)
# sfi is the specular-free image.
epsilon = startEps
step = 0.01
while(epsilon >= 0.0):
# if verboseFlag:
# print('*')
diffuse, srcPixelStatus = iteration(
diffuse, srcPixelStatus, sfi, epsilon, verboseFlag)
epsilon -= step
# if verboseFlag:
# print('ep: %f' % epsilon)
speckleResidue = srcImage - diffuse
# speckleResidue is 3D but for every pixel all channels have the same
# value.
return sfi, diffuse, speckleResidue
def specular_free_image(src, srcPixelStatus=None):
"""Generates specular-free version of input RGB color image src.
Args:
src: numpy array of shape (3, maxY, maxX) containing a RGB image.
srcPixelStatus: numpy array of shape (maxX, maxY) containing a marker
per pixel, indicating the type of pixel. This array is updated
inside this function, so if the input param. is None, it is first
allocated and initialized to 0-values.
Outputs:
srcPixelStatus: numpy array of shape (maxX, maxY) containing a marker
per pixel, indicating the type of pixel.
sfi: numpy array of shape (3, maxY, maxX) containing the specular-free
image corresponding to src.
srcMaxChroma: numpy array of shape (maxX, maxY) containing the max.
chroma for each pixel.
srcMax: numpy array of shape (maxX, maxY) containing the max. among the
3 color-intensities, for each pixel in src.
srcTotal: numpy array of shape (maxX, maxY) containing pixel-wise sum
of color-intensities in src.
"""
# allocate output image
cLambda = 0.6 # arbitrary constant. See paper referenced above.
camDark = 10.0 # threshold to determine if a pixel is too dark
lambdaConst = 3.0 * cLambda - 1.0
if srcPixelStatus is None:
srcPixelStatus = np.zeros((src.shape[1], src.shape[2]))
else:
assert(
src.shape[1:-1] == srcPixelStatus.shape), "specular_free_image()" \
":: srcPixelStatus should be None, or should match the " \
"pixel-layout of src."
srcPixelStatus[np.logical_and.reduce(src < camDark, 0)] = G_CAMERA_DARK
srcMaxChroma, srcMax, srcTotal = max_chroma(src)
numer = srcMax * (3.0 * srcMaxChroma - 1.0)
denom = srcMaxChroma * lambdaConst
old_settings = np.seterr(divide='ignore', invalid='ignore')
dI = np.divide(numer, denom)
np.seterr(**old_settings)
sI = (srcTotal - dI) / 3.0
# src: 3d array (rgb image); sI: 2D array matching pixel-layout of src
drgb = src.astype(float) - sI
drgb[np.where(np.isinf(drgb))] = 0
drgb[np.where(np.isnan(drgb))] = 0
drgb[np.where(drgb < 0)] = 0
drgb[np.where(drgb > 255)] = 255
sfi = drgb
return srcPixelStatus, sfi, srcMaxChroma, srcMax, srcTotal
def iteration(src, srcPixelStatus, sfi, epsilon, verboseFlag=True):
"""Iteratively converts each specular-pixel to diffuse.
Args:
src: numpy array of shape (3, maxY, maxX) containing a RGB image.
srcPixelStatus: numpy array of shape (maxX, maxY) containing a marker
per pixel, indicating the type of pixel.
sfi: numpy array of shape (3, maxY, maxX) containing the speckle-free
image corresponding to src
epsilon: floating-point (small) value.
verboseFlag: indicator to print something in every loop.
Outputs:
src: numpy array of shape (3, maxY, maxX) containing updated input
image
srcPixelStatus: numpy array of shape (maxX, maxY) containing updated
pixel-markers
"""
thR = 0.1
thG = 0.1
pcount = 0
count, srcPixelStatus = init_labels(src, sfi, epsilon, srcPixelStatus)
while(1):
maxY, maxX = src.shape[-2:]
srcMaxChroma, srcMax, srcTotal = max_chroma(src)
srcChroma, srcTotal = rgb_chroma(src, srcTotal)
red_chroma_diff_x = np.diff(srcChroma[0, :, :], axis=1)
red_chroma_diff_y = np.diff(srcChroma[0, :, :], axis=0)
grn_chroma_diff_x = np.diff(srcChroma[1, :, :], axis=1)
grn_chroma_diff_y = np.diff(srcChroma[1, :, :], axis=0)
# a non-complete attempt to remove the for loop below
# # find non G_CAMERA_DARK pixels
# non_g_camera_dark = (srcPixelStatus != G_CAMERA_DARK)
# non_g_camera_dark[-1, :] = False
# non_g_camera_dark[:, -1] = False
# g_specularx = (non_g_camera_dark) & \
# (srcPixelStatus == G_SPECULARX)
# g_speculary = (non_g_camera_dark) & \
# (srcPixelStatus == G_SPECULARY)
# '''for specular y'''
# # if it is a boundary in x
# boundary_x = np.zeros_like(g_specularx)
# boundary_x[:-1, :-1] = g_specularx[:-1, :-1] & \
# (np.fabs(red_chroma_diff_x[:-1, :]) > thR) & \
# (np.fabs(grn_chroma_diff_x[:-1, :]) > thG)
# srcPixelStatus[boundary_x] = G_BOUNDARY
# # if it is noise in x
# srcMaxChromaDiffX = np.diff(srcMaxChroma, axis=1)
# srcMaxChromaAbsDiffX = np.fabs(srcMaxChromaDiffX)
# noise_mask_x = g_specularx & (~boundary_x)
# noise_mask_x[:-1, :-1] = noise_mask_x[:-1, :-1] & \
# (srcMaxChromaAbsDiffX[:-1, :] < 0.01)
# srcPixelStatus[noise_mask_x] = G_NOISE
# # if it is a boundary in x
# boundary_y = np.zeros_like(g_speculary)
# boundary_y[:-1, :-1] = g_speculary[:-1, :-1] & \
# (np.fabs(red_chroma_diff_y[:, :-1]) > thR) & \
# (np.fabs(grn_chroma_diff_y[:, :-1]) > thG)
# srcPixelStatus[boundary_y] = G_BOUNDARY
# # if it is noise in x
# srcMaxChromaDiffY = np.diff(srcMaxChroma, axis=0)
# srcMaxChromaAbsDiffY = np.fabs(srcMaxChromaDiffY)
# noise_mask_y = g_speculary & (~boundary_y)
# noise_mask_y[:-1, :-1] = noise_mask_y[:-1, :-1] & \
# (srcMaxChromaAbsDiffY[:, :-1] < 0.01)
# srcPixelStatus[noise_mask_y] = G_NOISE
# # if it is not noise or boundary
# boundary_x = np.zeros_like(g_specularx)
# boundary_x[:-1, :-1] = g_specularx[:-1, :-1] & \
# (np.fabs(red_chroma_diff_x[:-1, :]) > thR) & \
# (np.fabs(grn_chroma_diff_x[:-1, :]) > thG)
# srcMaxChromaDiffX = np.diff(srcMaxChroma, axis=1)
# srcMaxChromaAbsDiffX = np.fabs(srcMaxChromaDiffX)
# noise_mask_x = g_specularx & (~boundary_x)
# noise_mask_x[:-1, :-1] = noise_mask_x[:-1, :-1] & \
# (srcMaxChromaAbsDiffX[:-1, :] < 0.01)
# non_noise_mask_x = g_specularx & (~boundary_x) & (~noise_mask_x)
# srcPixelStatus[non_noise_mask_x] = G_DIFFUSE
# non_noise_mask_next_x = np.roll(non_noise_mask_x, 1, axis=1)
# srcPixelStatus[non_noise_mask_next_x] = G_DIFFUSE
# boundary_y = np.zeros_like(g_speculary)
# boundary_y[:-1, :-1] = g_speculary[:-1, :-1] & \
# (np.fabs(red_chroma_diff_y[:, :-1]) > thR) & \
# (np.fabs(grn_chroma_diff_y[:, :-1]) > thG)
# srcMaxChromaDiffY = np.diff(srcMaxChroma, axis=0)
# srcMaxChromaAbsDiffY = np.fabs(srcMaxChromaDiffY)
# noise_mask_y = g_speculary & (~boundary_y)
# noise_mask_y[:-1, :-1] = noise_mask_y[:-1, :-1] & \
# (srcMaxChromaAbsDiffY[:, :-1] < 0.01)
# non_noise_mask_y = g_speculary & (~boundary_y) & (~noise_mask_y)
# srcPixelStatus[non_noise_mask_y] = G_DIFFUSE
# non_noise_mask_next_y = np.roll(non_noise_mask_y, 1, axis=0)
# srcPixelStatus[non_noise_mask_next_y] = G_DIFFUSE
# # if it is not boundary or noise
# pos_chroma_maskx = (srcMaxChromaDiffX[:-1, :] > 0)
# reduce_mask_pos_x = non_noise_mask_x.copy()
# reduce_mask_pos_x[:-1, :-1] = reduce_mask_pos_x[:-1, :-1] & \
# pos_chroma_maskx
# reduce_mask_pos_next_x = np.roll(reduce_mask_pos_x, 1, axis=1)
# iro = np.moveaxis(np.moveaxis(src, 0, -1)[reduce_mask_pos_x], -1, 0)
# refMaxChroma = srcMaxChroma[reduce_mask_pos_next_x]
# iroTotal = srcTotal[reduce_mask_pos_x]
# iroMax = srcMax[reduce_mask_pos_x]
# iroMaxChroma = srcMaxChroma[reduce_mask_pos_x]
# pStat, iroRes = specular_to_diffuse_vectorized(
# iro, iroMax, iroMaxChroma, iroTotal, refMaxChroma)
# iro[:, pStat != G_NOISE] = iroRes[:, pStat != G_NOISE]
# pos_chroma_maskx = ~pos_chroma_maskx
# reduce_mask_pos_x = non_noise_mask_x.copy()
# reduce_mask_pos_x[:-1, :-1] = reduce_mask_pos_x[:-1, :-1] & \
# pos_chroma_maskx
# reduce_mask_pos_next_x = np.roll(reduce_mask_pos_x, 1, axis=1)
# iro = np.moveaxis(np.moveaxis(src, 0, -1)[reduce_mask_pos_next_x],
# -1, 0)
# refMaxChroma = srcMaxChroma[reduce_mask_pos_x]
# iroTotal = srcTotal[reduce_mask_pos_next_x]
# iroMax = srcMax[reduce_mask_pos_next_x]
# iroMaxChroma = srcMaxChroma[reduce_mask_pos_next_x]
# pStat, iroRes = specular_to_diffuse_vectorized(
# iro, iroMax, iroMaxChroma, iroTotal, refMaxChroma)
# iro[:, pStat != G_NOISE] = iroRes[:, pStat != G_NOISE]
# # if it is not boundary or noise
# pos_chroma_masky = (srcMaxChromaDiffY[:, :-1] > 0)
# reduce_mask_pos_y = non_noise_mask_y.copy()
# reduce_mask_pos_y[:-1, :-1] = reduce_mask_pos_y[:-1, :-1] & \
# pos_chroma_masky
# reduce_mask_pos_next_y = np.roll(reduce_mask_pos_y, 1, axis=1)
# iro = np.moveaxis(np.moveaxis(src, 0, -1)[reduce_mask_pos_y], -1, 0)
# refMaxChroma = srcMaxChroma[reduce_mask_pos_next_y]
# iroTotal = srcTotal[reduce_mask_pos_y]
# iroMax = srcMax[reduce_mask_pos_y]
# iroMaxChroma = srcMaxChroma[reduce_mask_pos_y]
# pStat, iroRes = specular_to_diffuse_vectorized(
# iro, iroMax, iroMaxChroma, iroTotal, refMaxChroma)
# iro[:, pStat != G_NOISE] = iroRes[:, pStat != G_NOISE]
# pos_chroma_masky = ~pos_chroma_masky
# reduce_mask_pos_y = non_noise_mask_y.copy()
# reduce_mask_pos_y[:-1, :-1] = reduce_mask_pos_y[:-1, :-1] & \
# pos_chroma_masky
# reduce_mask_pos_next_y = np.roll(reduce_mask_pos_y, 1, axis=1)
# iro = np.moveaxis(np.moveaxis(src, 0, -1)[reduce_mask_pos_next_y],
# -1, 0)
# refMaxChroma = srcMaxChroma[reduce_mask_pos_y]
# iroTotal = srcTotal[reduce_mask_pos_next_y]
# iroMax = srcMax[reduce_mask_pos_next_y]
# iroMaxChroma = srcMaxChroma[reduce_mask_pos_next_y]
# pStat, iroRes = specular_to_diffuse_vectorized(
# iro, iroMax, iroMaxChroma, iroTotal, refMaxChroma)
# iro[:, pStat != G_NOISE] = iroRes[:, pStat != G_NOISE]
for y in range(maxY - 1):
for x in range(maxX - 1):
current_pixel = srcPixelStatus[y, x]
if(current_pixel == G_CAMERA_DARK):
continue
drx = red_chroma_diff_x[y, x]
dgx = grn_chroma_diff_x[y, x]
dry = red_chroma_diff_y[y, x]
dgy = grn_chroma_diff_y[y, x]
if(current_pixel == G_SPECULARX):
# if it is a boundary in the x direction
if (abs(drx) > thR) and (abs(dgx) > thG):
# pixel right
srcPixelStatus[y, x] = G_BOUNDARY
continue
# if it is a noise
if abs(srcMaxChroma[y, x] - srcMaxChroma[y, x + 1]) < 0.01:
srcPixelStatus[y, x] = G_NOISE
continue
# reduce the specularity at x direction
if srcMaxChroma[y, x] < srcMaxChroma[y, x + 1]:
iro = src[:, y, x]
# pStat = current_pixel
refMaxChroma = srcMaxChroma[y, x + 1]
iroTotal = srcTotal[y, x]
iroMax = srcMax[y, x]
iroMaxChroma = srcMaxChroma[y, x]
pStat, iroRes = specular_to_diffuse(
iro, iroMax, iroMaxChroma, iroTotal, refMaxChroma)
# update pixelStatus only if
# zSpecular2Diffuse() returned pStat as
# G_NOISE.
if pStat != G_NOISE:
src[:, y, x] = iroRes
# else:
# srcPixelStatus[y, x] = pStat
else:
iro = src[:, y, x + 1]
# pStat = srcPixelStatus[y, x + 1]
refMaxChroma = srcMaxChroma[y, x]
iroTotal = srcTotal[y, x + 1]
iroMax = srcMax[y, x + 1]
iroMaxChroma = srcMaxChroma[y, x + 1]
pStat, iroRes = specular_to_diffuse(
iro, iroMax, iroMaxChroma, iroTotal, refMaxChroma)
# update pixelStatus only if
# zSpecular2Diffuse() returned pStat as
# G_NOISE.
if pStat != G_NOISE:
src[:, y, x + 1] = iroRes
# else:
# srcPixelStatus[y, x + 1] = pStat
srcPixelStatus[y, x] = G_DIFFUSE
srcPixelStatus[y, x + 1] = G_DIFFUSE
if(current_pixel == G_SPECULARY):
# if it is a boundary in the y direction
if (abs(dry) > thR) and (abs(dgy) > thG):
# pixel right
srcPixelStatus[y, x] = G_BOUNDARY
continue
# if it is a noise
if abs(srcMaxChroma[y, x] - srcMaxChroma[y + 1, x]) < 0.01:
srcPixelStatus[y, x] = G_NOISE
continue
# reduce the specularity in y direction
if srcMaxChroma[y, x] < srcMaxChroma[y + 1, x]:
iro = src[:, y, x]
pStat = current_pixel
refMaxChroma = srcMaxChroma[y + 1, x]
iroTotal = srcTotal[y, x]
iroMax = srcMax[y, x]
iroMaxChroma = srcMaxChroma[y, x]
pStat, iroRes = specular_to_diffuse(
iro, iroMax, iroMaxChroma, iroTotal, refMaxChroma)
# C call:
# zSpecular2Diffuse(src(y,x),src(y+1,x).zMaxChroma())
# update pixelStatus only if
# zSpecular2Diffuse() returned pStat as
# G_NOISE.
if pStat == G_NOISE:
srcPixelStatus[y, x] = pStat
else:
src[:, y, x] = iroRes
else:
iro = src[:, y + 1, x]
pStat = srcPixelStatus[y + 1, x]
pMaxChroma = srcMaxChroma[y + 1, x]
iroTotal = srcTotal[y + 1, x]
iroMax = srcMax[y + 1, x]
iroMaxChroma = srcMaxChroma[y + 1, x]
pStat, iroRes = specular_to_diffuse(
iro, iroMax, iroMaxChroma, iroTotal, pMaxChroma)
# update pixelStatus only if
# zSpecular2Diffuse() returned pStat as
# G_NOISE.
if pStat == G_NOISE:
srcPixelStatus[y + 1, x] = pStat
else:
src[:, y + 1, x] = iroRes
srcPixelStatus[y, x] = G_DIFFUSE
srcPixelStatus[y + 1, x] = G_DIFFUSE
pcount = count
count, srcPixelStatus = init_labels(src, sfi, epsilon, srcPixelStatus)
# Robby Tan's original C++ code checks if count<0, but that doesn't
# make sense as count cannot be negative.
if(count == 0 or pcount <= count):
break # break out of the while-loop
srcPixelStatus = reset_labels(srcPixelStatus)
return src, srcPixelStatus
def init_labels(src, sfi, epsilon, srcPixelStatus):
"""Generates initial labels for all pixels in src (input RGB image).
Args:
src: numpy array of shape (3, maxY, maxX) containing a RGB image.
sfi: numpy array of shape (3, maxY, maxX) containing a speckle-free
image corresponding to src.
epsilon: positive floating point (small) value
srcPixelStatus: numpy array of shape (maxX, maxY) containing pixel-
markers corresponding to src.
Returns:
count: number of pixels marked as specular in src.
srcPixelStatus: numpy array of shape (maxX, maxY) containing updated
pixel-markers corresponding to src.
"""
old_settings = np.seterr(divide='ignore', invalid='ignore')
# to have initial labels
zTotalSrc = np.sum(src, axis=0)
diff_x_src = np.diff(zTotalSrc, axis=1)
diff_y_src = np.diff(zTotalSrc, axis=0)
zTotalSfi = np.sum(sfi, axis=0)
diff_x_sfi = np.diff(zTotalSfi, axis=1)
diff_y_sfi = np.diff(zTotalSfi, axis=0)
dlog_src_x = np.log(np.fabs(diff_x_src))
dlog_src_y = np.log(np.fabs(diff_y_src))
dlog_sfi_x = np.log(np.fabs(diff_x_sfi))
dlog_sfi_y = np.log(np.fabs(diff_y_sfi))
dlogx = np.fabs(dlog_src_x - dlog_sfi_x)
dlogy = np.fabs(dlog_src_y - dlog_sfi_y)
# maxY = src.shape[1]
# maxX = src.shape[2]
valid_values = (G_BOUNDARY, G_NOISE, G_CAMERA_DARK, G_DIFFUSE)
notvalid_mask = np.in1d(
srcPixelStatus[1:-1, 1:-1], valid_values,
invert=True).reshape(srcPixelStatus.shape[0] - 2, -1)
dlogx_mask = (notvalid_mask) & (dlogx[1:-1, 1:] > epsilon)
dlogy_mask = (notvalid_mask) & (dlogy[1:, 1:-1] > epsilon) & \
(~(dlogx_mask))
diffuse_mask = (notvalid_mask) & (~dlogx_mask) & (~dlogy_mask)
count = notvalid_mask.sum()
srcPixelStatus[1:-1, 1:-1][dlogx_mask] = G_SPECULARX
srcPixelStatus[1:-1, 1:-1][dlogy_mask] = G_SPECULARY
srcPixelStatus[1:-1, 1:-1][diffuse_mask] = G_DIFFUSE
np.seterr(**old_settings)
return count, srcPixelStatus # count is the number of specular pixels
def specular_to_diffuse(iro, iroMax, iroMaxChroma, iroTotal, refMaxChroma):
"""Converts a color-pixel from speckled to diffuse, by subtracting a
certain amount from its intensity value in each color channel.
Args:
iro: 3-element column vector containing the rgb-color values of the
pixel to be processed.
iroMax: max value among the elements of iro
iroMaxChroma: max-chroma for this pixel
iroTotal: sum of the 3 elements of iro.
refMaxChroma: chroma-value of a neighboring pixel for comparison
Returns:
pixelStatus: a value (marker) indicating whether the pixel is
considered as noise or diffuse, after processing.
iro: updated pixel-color-values.
"""
c = iroMaxChroma
pixelStatus = 0 # arbitrary initialization
numr = (iroMax * (3.0 * c - 1.0))
denm = (c * (3.0 * refMaxChroma - 1.0))
if abs(denm) > 0.000000001: # to avoid div. by zero.
dI = numr / denm
sI = (iroTotal - dI) / 3.0
nrgb = iro - sI
if np.any(nrgb < 0):
pixelStatus = G_NOISE
else:
iro = nrgb
else:
pixelStatus = G_NOISE
return pixelStatus, iro
# def specular_to_diffuse_vectorized(iro, iroMax, iroMaxChroma, iroTotal,
# refMaxChroma):
# """Converts a color-pixel from speckled to diffuse, by subtracting a
# certain amount from its intensity value in each color channel.