visual_regression.sh 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256
  1. #!/bin/bash
  2. # This script runs a visual regression test on all the images
  3. # generated from OSMD samples (npm run generate:current and npm run generate:blessed)
  4. #
  5. # inspired by and adapted from Vexflow's visual regression tests.
  6. #
  7. # Prerequisites: ImageMagick
  8. #
  9. # On OSX: $ brew install imagemagick
  10. # On Linux: $ apt-get install imagemagick
  11. #
  12. # Usage:
  13. #
  14. #
  15. # First generate the known good or previous state PNG images you want to compare to, e.g. the develop branch or last release:
  16. # (Server has to be running for this: npm start)
  17. #
  18. # npm run generate:blessed
  19. #
  20. # Make changes in OSMD, then generate your new images:
  21. #
  22. # npm run generate:current
  23. #
  24. # Run the regression tests against the blessed images in tests/blessed.
  25. #
  26. # npm run test:visual
  27. # # npm will navigate to the base folder automatically
  28. #
  29. # # or: (this should be done from the main OSMD folder)
  30. # # sh test/Util/visual_regression.sh
  31. #
  32. # Check visual_regression/diff/results.txt for results. This file is sorted
  33. # by PHASH difference (most different files on top.) The composite diff
  34. # images for failed tests (i.e., PHASH > 1.0) are stored in visual_regression/diff.
  35. #
  36. # If you are satisfied with the differences, copy *.png from visual_regression/current
  37. # into visual_regression/blessed, and submit your change.
  38. # PNG viewer on OSX. Switch this to whatever your system uses.
  39. # VIEWER=open
  40. # Show images over this PHASH threshold. This is probably too low, but
  41. # a good first pass.
  42. THRESHOLD=0.01
  43. # Directories. You might want to change BASE, if you're running from a
  44. # different working directory. (only necessary if you're running the script manually, i.e. not from npm run test:visual)
  45. if [ "$1" == "" ]
  46. then
  47. BASEFOLDER="./visual_regression"
  48. else
  49. BASEFOLDER=$1
  50. fi
  51. BLESSED=$BASEFOLDER/blessed
  52. CURRENT=$BASEFOLDER/current
  53. DIFF=$BASEFOLDER/diff
  54. # All results are stored here.
  55. RESULTS=$DIFF/results.txt
  56. WARNINGS=$DIFF/warnings.txt
  57. # If no prefix is provided, test all images.
  58. if [ "$2" == "" ]
  59. then
  60. files=*.png
  61. else
  62. files=$2*.png
  63. printf "only processing images matching bash string (not regex): ${files}\n"
  64. fi
  65. # some sanity checks: check if some png images are in the right folder and warn if not. doesn't make sure there are actual, correct png images though.
  66. folderWarningStringMsg="Also, please run this npm script from the base OSMD folder. (npm run test:visual should do this automatically)
  67. Exiting without running visual regression tests.\n"
  68. # check if current directory exists / started from base OSMD folder
  69. if [ ! -e "$CURRENT" ]
  70. then
  71. printf "Warning: directory ${CURRENT} missing. Please run npm run generate:current (and if necessary npm run generate:blessed) first.
  72. ${folderWarningStringMsg}"
  73. exit 1
  74. fi
  75. # check if blessed directory exists / started from base OSMD folder
  76. if [ ! -e "$BLESSED" ]
  77. then
  78. printf "Warning: directory ${BLESSED} missing. Please run npm run generate:blessed first (or otherwise get the blessed images).
  79. ${folderWarningStringMsg}"
  80. exit 1
  81. fi
  82. # note: ls returns errors if the directory doesn't exist
  83. totalCurrentImages=`ls -l $CURRENT/*.png | wc -l | sed 's/[[:space:]]//g'`
  84. totalBlessedImages=`ls -l $BLESSED/*.png | wc -l | sed 's/[[:space:]]//g'`
  85. # check if there are some current images
  86. if [ "$totalCurrentImages" -lt 1 ]
  87. then
  88. printf "Warning: Found no pngs in ${CURRENT}. Please run npm run generate (and if necessary npm run blessed) first.
  89. ${folderWarningStringMsg}"
  90. exit 1
  91. fi
  92. # check if there are some blessed images
  93. if [ "$totalBlessedImages" -lt 1 ]
  94. then
  95. printf "Warning: Found no pngs in ${BLESSED}. Please run npm run blessed first, ideally on the repository's develop state.
  96. ${folderWarningStringMsg}"
  97. exit 1
  98. fi
  99. # check that #currentImages == #blessedImages (will continue anyways)
  100. if [ ! "$totalCurrentImages" -eq "$totalBlessedImages" ]
  101. then
  102. printf "Warning: Number of current images (${totalCurrentImages}) is not the same as blessed images (${totalBlessedImages}). Continuing anyways.\n"
  103. else
  104. printf "Found ${totalCurrentImages} current and ${totalBlessedImages} blessed png files (not tested if valid). Continuing.\n"
  105. fi
  106. mkdir -p $DIFF
  107. if [ -e "$RESULTS" ]
  108. then
  109. rm $DIFF/*
  110. fi
  111. touch $RESULTS
  112. touch $RESULTS.pass
  113. touch $RESULTS.fail
  114. touch $WARNINGS
  115. # Number of simultaneous jobs
  116. nproc=$(sysctl -n hw.physicalcpu 2> /dev/null || nproc)
  117. if [ -n "$NPROC" ]; then
  118. nproc=$NPROC
  119. fi
  120. total=`ls -l $BLESSED/$files | wc -l | sed 's/[[:space:]]//g'`
  121. echo "Running $total tests with threshold $THRESHOLD (nproc=$nproc)..."
  122. function ProgressBar {
  123. let _progress=(${1}*100/${2}*100)/100
  124. let _done=(${_progress}*4)/10
  125. let _left=40-$_done
  126. _fill=$(printf "%${_done}s")
  127. _empty=$(printf "%${_left}s")
  128. printf "\rProgress : [${_fill// /#}${_empty// /-}] ${_progress}%%"
  129. }
  130. function diff_image() {
  131. local image=$1
  132. local name=`basename $image .png`
  133. local blessed=$BLESSED/$name.png
  134. local current=$CURRENT/$name.png
  135. local diff=$current-temp
  136. if [ ! -e "$current" ]
  137. then
  138. echo "Warning: $name.png missing in $CURRENT." >$diff.warn
  139. return
  140. fi
  141. if [ ! -e "$blessed" ]
  142. then
  143. return
  144. fi
  145. cp $blessed $diff-a.png
  146. cp $current $diff-b.png
  147. # Calculate the difference metric and store the composite diff image.
  148. local hash=`compare -metric PHASH -highlight-color '#ff000050' $diff-b.png $diff-a.png $diff-diff.png 2>&1`
  149. local isGT=`echo "$hash > $THRESHOLD" | bc -l`
  150. if [ "$isGT" == "1" ]
  151. then
  152. # Add the result to results.text
  153. echo $name $hash >$diff.fail
  154. # Threshold exceeded, save the diff and the original, current
  155. cp $diff-diff.png $DIFF/$name.png
  156. cp $diff-a.png $DIFF/$name'_'Blessed.png
  157. cp $diff-b.png $DIFF/$name'_'Current.png
  158. echo
  159. echo "Test: $name"
  160. echo " PHASH value exceeds threshold: $hash > $THRESHOLD"
  161. echo " Image diff stored in $DIFF/$name.png"
  162. # $VIEWER "$diff-diff.png" "$diff-a.png" "$diff-b.png"
  163. # echo 'Hit return to process next image...'
  164. # read
  165. else
  166. echo $name $hash >$diff.pass
  167. fi
  168. rm -f $diff-a.png $diff-b.png $diff-diff.png
  169. }
  170. function wait_jobs () {
  171. local n=$1
  172. while [[ "$(jobs -r | wc -l)" -ge "$n" ]] ; do
  173. # echo ===================================== && jobs -lr
  174. # wait the oldest job.
  175. local pid_to_wait=`jobs -rp | head -1`
  176. # echo wait $pid_to_wait
  177. wait $pid_to_wait &> /dev/null
  178. done
  179. }
  180. count=0
  181. for image in $CURRENT/$files
  182. do
  183. count=$((count + 1))
  184. ProgressBar ${count} ${total}
  185. wait_jobs $nproc
  186. diff_image $image &
  187. done
  188. wait
  189. cat $CURRENT/*.warn 1>$WARNINGS 2>/dev/null
  190. rm -f $CURRENT/*.warn
  191. ## Check for files newly built that are not yet blessed.
  192. for image in $CURRENT/$files
  193. do
  194. name=`basename $image .png`
  195. blessed=$BLESSED/$name.png
  196. current=$CURRENT/$name.png
  197. if [ ! -e "$blessed" ]
  198. then
  199. echo " Warning: $name.png missing in $BLESSED." >>$WARNINGS
  200. fi
  201. done
  202. num_warnings=`cat $WARNINGS | wc -l`
  203. cat $CURRENT/*.fail 1>$RESULTS.fail 2>/dev/null
  204. num_fails=`cat $RESULTS.fail | wc -l`
  205. rm -f $CURRENT/*.fail
  206. # Sort results by PHASH
  207. sort -r -n -k 2 $RESULTS.fail >$RESULTS
  208. sort -r -n -k 2 $CURRENT/*.pass 1>>$RESULTS 2>/dev/null
  209. rm -f $CURRENT/*.pass $RESULTS.fail $RESULTS.pass
  210. echo
  211. echo Results stored in $DIFF/results.txt
  212. echo All images with a difference over threshold, $THRESHOLD, are
  213. echo available in $DIFF, sorted by perceptual hash.
  214. echo
  215. if [ "$num_warnings" -gt 0 ]
  216. then
  217. echo
  218. echo "You have $num_warnings warning(s):"
  219. cat $WARNINGS
  220. fi
  221. if [ "$num_fails" -gt 0 ]
  222. then
  223. echo "You have $num_fails fail(s):"
  224. head -n $num_fails $RESULTS
  225. else
  226. echo "Success - All diffs under threshold!"
  227. fi