作成した関数
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 ) )
コメント