Page 1 of 1

Average color by row (bash)

Posted: 2019-01-28T12:26:10-07:00
by samuelwn
I'm looking for a way to get the average color of each row for a grayscale image. I've gotten a functional solution, but it's rather slow and inelegant. I'm sure that there's a better way to do this (likely within a single ImageMagick command), but I'm unable to figure it out. Any assistance would be greatly appreciated.

Current solution:

Code: Select all

imageHeight="$(magick identify -format "%[fx:h]" "$f")"
rows="$(convert "$f" txt:)"
rowMeans=()

# example of `rows` content:
# 0,0: (150,150,150)  #969696  gray(150)
# 1,0: (154,154,154)  #9A9A9A  gray(154)
# 2,0: (154,154,154)  #9A9A9A  gray(154)

for rowNum in `seq 0 $(( ${imageHeight} - 1 ))`; do
    # Read the pixel value for each row, and store the value in an array
    pixArr=(`echo "$rows" | grep ",${rowNum}:" |  awk 'BEGIN { FS="[,]" } {print $3}'`)
    
    # Append each value in the array with a '+' and calculate the sum
    #   (this causes the last value to have a trailing '+', so it is added to '0')
    rowSum=$(echo "${pixArr[@]/%/+}"0 | bc -l)
    
    # Divide the sum by the total number of elements and add the value to the array
    rowMeans=(${rowMeans} `echo $((rowSum / ${#pixArr[@]} )) ` )
done

Re: Average color by row (bash)

Posted: 2019-01-28T12:44:56-07:00
by fmw42
To get the average for each row of an image, just scale it to 1 column and send that data to txt: for output. The -scale functions does a simple average.

Code: Select all

convert image.suffix -scale 1x! txt:
For example, using the imagemagick internal image rose:, it would be

Code: Select all

convert rose: -scale 1x! txt:
# ImageMagick pixel enumeration: 1,46,65535,srgb
0,0: (27128,16195,14979)  #6A3F3A  srgb(106,63,58)
0,1: (26339,15732,14554)  #663D39  srgb(102,61,57)
0,2: (23956,15020,14139)  #5D3A37  srgb(93,58,55)
0,3: (23750,16624,15695)  #5C413D  srgb(92,65,61)
0,4: (23475,18177,16132)  #5B473F  srgb(91,71,63)
0,5: (22414,18515,15508)  #57483C  srgb(87,72,60)
0,6: (21683,18845,15607)  #54493D  srgb(84,73,61)
0,7: (23549,20101,16503)  #5C4E40  srgb(92,78,64)
0,8: (31908,19672,17729)  #7C4D45  srgb(124,77,69)
0,9: (38388,19785,19257)  #954D4B  srgb(149,77,75)
0,10: (41050,21614,21107)  #A05452  srgb(160,84,82)
0,11: (42578,22855,22465)  #A65957  srgb(166,89,87)
0,12: (45126,24727,25237)  #B06062  srgb(176,96,98)
0,13: (47696,25740,27293)  #BA646A  srgb(186,100,106)
0,14: (49083,26251,27433)  #BF666B  srgb(191,102,107)
0,15: (49649,26746,27114)  #C1686A  srgb(193,104,106)
0,16: (48735,25803,25355)  #BE6463  srgb(190,100,99)
0,17: (47795,23255,22062)  #BA5A56  srgb(186,90,86)
0,18: (47035,21180,19440)  #B7524C  srgb(183,82,76)
0,19: (47589,21621,19594)  #B9544C  srgb(185,84,76)
0,20: (46877,21360,18746)  #B65349  srgb(182,83,73)
0,21: (46851,21856,19752)  #B6554D  srgb(182,85,77)
0,22: (47453,22965,20975)  #B95952  srgb(185,89,82)
0,23: (47325,23563,21144)  #B85C52  srgb(184,92,82)
0,24: (45904,23005,21386)  #B35A53  srgb(179,90,83)
0,25: (44087,21456,20828)  #AC5351  srgb(172,83,81)
0,26: (43279,21415,20766)  #A85351  srgb(168,83,81)
0,27: (42596,21885,20850)  #A65551  srgb(166,85,81)
0,28: (41627,21878,19811)  #A2554D  srgb(162,85,77)
0,29: (40584,21838,18133)  #9E5547  srgb(158,85,71)
0,30: (39670,21283,16323)  #9A5340  srgb(154,83,64)
0,31: (38341,20604,15549)  #95503D  srgb(149,80,61)
0,32: (35811,20428,15137)  #8B4F3B  srgb(139,79,59)
0,33: (34438,21324,16051)  #86533E  srgb(134,83,62)
0,34: (33972,21331,16485)  #845340  srgb(132,83,64)
0,35: (32786,20931,16455)  #805140  srgb(128,81,64)
0,36: (30858,21089,16745)  #785241  srgb(120,82,65)
0,37: (31281,22407,18625)  #7A5748  srgb(122,87,72)
0,38: (32162,24955,21140)  #7D6152  srgb(125,97,82)
0,39: (32371,26607,22994)  #7E6859  srgb(126,104,89)
0,40: (33028,28450,25355)  #816F63  srgb(129,111,99)
0,41: (33542,30025,27191)  #83756A  srgb(131,117,106)
0,42: (33737,31159,28395)  #83796E  srgb(131,121,110)
0,43: (33873,32661,29775)  #847F74  srgb(132,127,116)
0,44: (35341,35631,32555)  #8A8B7F  srgb(138,139,127)
0,45: (35892,36670,32925)  #8C8F80  srgb(140,143,128)
replace rose: with your image with suffix.

Re: Average color by row (bash)

Posted: 2019-01-28T12:55:37-07:00
by samuelwn
I literally did a forehead-slap while reading that.
Thank you!!

Re: Average color by row (bash)

Posted: 2019-01-28T13:04:48-07:00
by snibgo
samuelwn wrote:I've gotten a functional solution, but it's rather slow and inelegant.
It also seems to be wrong. It seems to give different answers from the inputs "xc:red", "xc:lime" and "xc:blue". But I'm no bash expert.

Re: Average color by row (bash)

Posted: 2019-01-28T14:31:28-07:00
by samuelwn
snibgo wrote: 2019-01-28T13:04:48-07:00 It seems to give different answers from the inputs "xc:red", "xc:lime" and "xc:blue". But I'm no bash expert.
The way that my previous solution worked was by parsing the text output, e.g.

Code: Select all

0,0: (150,150,150)  #969696  gray(150)
and snipping out the value between the 2nd and 3rd comma (i.e. the middle 150 in '(150,150,150)' ). It's a clunky way of doing things and only worked because the images I'm working with are grayscale.

Re: Average color by row (bash)

Posted: 2019-01-28T14:53:02-07:00
by snibgo
samuelwn wrote:...because the images I'm working with are grayscale.
Ah, that figures, thanks.