作成した関数
hist.match = function( cimg, target.hist = NULL, return.image = T, save.dir = "NULL" ){
if( !is.null( save.dir ) ){
dir.create( file.path( save.dir ), showWarnings = F )
}
if( class( cimg )[ 1 ] != "list" ){
cimg = list( image.png = cimg )
}
if( is.null( target.hist ) ){
h = lapply( cimg, hist.create )
target.hist = hist.average( h )
}
progress = 1
staging = unique( floor( seq( from = 1, to = length( cimg ), length.out = 5 ) ) )
cat( "[hist.match] Progress: " )
for( i in 1:length( cimg ) ){
# Display progress
if( i == staging[ progress ] ){
cat( paste0( sprintf( "%1.0f", 100 * ( i - 1 ) / length( cimg ) ), "% ... " ) )
progress = progress + 1
}
# Matching routine
target = hist.scale( target.hist, sum( h[[ i ]] ) )
if( spectrum( cimg[[ i ]] ) < 3 ){
L = as.data.frame( cimg[[ i ]] )
L = L[ order( L$value), ]
L$value = hist.serialize( target ) / 255
im = as.cimg( L, dim = dim( cimg[[ i ]] ) )
} else if( spectrum( cimg[[ i ]] ) >= 3 ){
cimg[[ i ]] = imsub( cimg[[ i ]], cc < 4 )
# saparate L and ab
imdf = as.data.frame( sRGBtoLab( cimg[[ i ]] ) )
imdf.L = subset( imdf, cc == 1 )
imdf.L = imdf.L[ order( imdf.L$value), ]
# match luminance
imdf.L$value = hist.serialize( target ) * 100 / 255
# reconstruct image
im = rbind( imdf.L, subset( imdf, cc > 1 ) )
im = LabtosRGB( as.cimg( im, dim = dim( cimg[[ i ]] ) ) )
}
if( return.image ){
cimg[[ i ]] = im
}
if( ! is.null( save.dir ) ){
imager::save.image( im, paste0( save.dir, "/", names( cimg )[ i ] ) )
}
}
cat( "done!\n" )
if( return.image ){
if( length( cimg ) == 1 ){
return( cimg[[ 1 ]] )
} else {
return( cimg )
}
}
}
hist.create = function( cimg, weight = "Lab" ){
L = clamp( round( luminance( cimg, weight = weight ) * 255 ), 0, 255 )
L = table( L )
h = vector( "integer", 256 )
h[ as.integer( names( L ) ) + 1 ] = L
return( h )
}
hist.scale = function( hist, target.n ){
h = round( hist * target.n / sum( hist ) )
diff = sum( h ) - target.n
if( diff != 0 ){
s = sort( h, decreasing = T, index.return = T )
h[ s$ix[ 1:abs( diff ) ] ] = h[ s$ix[ 1:abs( diff ) ] ] - sign( diff )
}
return( h )
}
hist.normalize = function( hist ){
return( hist * 1 / sum( hist ) )
}
hist.serialize = function( hist ){
lum.values = vector( "numeric", sum( hist ) )
index = 1
for( l in 1:256 ){
if( hist[ l ] == 0 ){
next
}
for( p in 1:hist[ l ] ){
lum.values[ index ] = l - 1
index = index + 1
}
}
return( lum.values )
}
hist.average = function( list.hist ){
h = lapply( list.hist, hist.normalize )
average.hist = vector( "numeric", 256 )
for( i in 1:length( h ) ){
average.hist = average.hist + h[[ i ]]
}
return( average.hist )
}
clamp = function( array, min = 0, max = 1 ){
array[ array < min ] = min
array[ array > max ] = max
return( array )
}
luminance = function( cimg, weight = "Lab" ){
if( spectrum( cimg ) < 3 ){
return( imsub( cimg, cc == 1 ) )
} else if( spectrum( cimg ) > 3 ){
cimg = imsub( cimg, cc < 4 )
}
# For definitions of lightness formulas, see https://en.wikipedia.org/wiki/HSL_and_HSV#Lightness
if( is.character( weight ) ){
if( weight == "Lab" ){
return( as.array( imsub( sRGBtoLab( cimg ), cc == 1 ) * 0.01 ) )
} else if( weight == "HSI" ){
return( as.array( imsub( RGBtoHSI( sRGBtoRGB( cimg ) ), cc == 3 ) ) )
} else if( weight == "HSV" ){
return( as.array( imsub( RGBtoHSV( sRGBtoRGB( cimg ) ), cc == 3 ) ) )
} else if( weight == "HSL" ){
return( as.array( imsub( RGBtoHSL( sRGBtoRGB( cimg ) ), cc == 3 ) ) )
} else if( weight == "Luma" ){
return( 0.3 * as.array( R( cimg ) ) + 0.59 * as.array( G( cimg ) ) + 0.11 * as.array( B( cimg ) ) )
} else {
print( "Caution: set a proper value for weight." )
return( as.array( cimg ) )
}
} else if( is.numeric( weight ) & length( weight ) == 3 ){
weight = weight / sum( weight )
return( weight[1] * as.array( R(cimg) ) +weight[2] * as.array( G(cimg) ) + weight[3] * as.array( B(cimg) ) )
} else {
print( "Caution: set a proper value for weight." )
return( as.array( cimg ) )
}
}
lum.mean = function( cimg, weight = "Lab" ){
return( mean( luminance( cimg, weight = weight ) ) )
}
lum.sd = function( cimg, weight = "Lab" ){
return( sd( luminance( cimg, weight = weight ) ) )
}
load.image.dir = function( dir, as.grayscale = F ){
names = list.files( dir, pattern = "\\.(jpg|jpeg|png|bmp|JPG|JPEG|PNG|BMP)$" )
l = vector( "list", length( names ) )
for( i in 1:length( names ) ){
l[[ i ]] = imager::load.image( paste0( dir, "/", names[ i ] ) )
if( as.grayscale ){
l[[ i ]] = as.grayscale( l[[ i ]] )
}
}
names( l ) = names
return( l )
}
使用例。
# display luminance histgram
h = hist.create( boats )
plot( h, type = "h", xlab = "Luminance", ylab = "Number of pixels" )
# averaging histgrams
im = list( imager::load.image( "../img/face.jpg" ), imager::load.image( "../img/forest.jpg" ) )
h = lapply( im, hist.create )
h2 = hist.average( h )
layout( t( 1:3 ) )
plot( h[[ 1 ]], type = "h", main = "face", xlab = "Luminance", ylab = "Number of pixels" )
plot( h[[ 2 ]], type = "h", main = "forest", xlab = "Luminance", ylab = "Number of pixels" )
plot( h2, type = "h", main = "averaged", xlab = "Luminance", ylab = "Number of pixels" )
layout( 1 )
# images and histgrams before the match
im = load.image.dir( "../img" )
im = lapply( im, imresize, scale = .5 )
# im = lapply( im, as.grayscale )
h = lapply( im, hist.create )
layout( matrix( 1:(length( im ) * 2), 2, length( im ), byrow = F ) )
for( i in 1:length( im ) ){
plot( im[[ i ]] )
plot( h[[ i ]], type = "h", xlab = "Luminance", ylab = "Number of pixels" )
}
layout( 1 )
# images and histgrams after the match
im = load.img.dir( "../img" )
im = lapply( im, imresize, scale = .5 )
im = hist.match( im )
h = lapply( im, hist.create )
layout( matrix( 1:(length( im ) * 2), 2, length( im ), byrow = F ) )
for( i in 1:length( im ) ){
plot( im[[ i ]] )
plot( h[[ i ]], type = "h", xlab = "Luminance", ylab = "Number of pixels" )
}
layout( 1 )
# mean and sd of luminance are almost identical to each other after the match
unlist( lapply( im, lum.mean ) )
unlist( lapply( im, lum.sd ) )
コメント