Page 1 of 2

Cut/crop sine wave shape into image?

Posted: 2015-12-04T17:49:46-07:00
by oeoeo
Hi all.

I feel like a did a pretty decent search but I didn't come up with much.

I'm trying to achieve something like this:
Image

Basically using imagemagick to cut a curve into an image.

I'm assuming something along these lines (one must rotate it twice to get to the bottom, correct?):

Code: Select all

convert my.gif  -rotate -90 -background none  -wave -10x75 \
                     -rotate +90  wave_y.jpg
...but, truthfully, I'm pretty unfamiliar with what I need to pass to the "-wave" flag to achieve this.

Thanks for any advice.

Re: Cut/crop sine wave shape into image?

Posted: 2015-12-04T19:22:07-07:00
by fmw42
What version of Imagemagick and what platform are you on? Please always provide that, since syntax differs.

If you are on Linux, Mac OSX or Windows with Cygwin and IM is at least version 6.4.8-8, then you can do the follow. (Sorry I do not know how to do that in Windows).

Note that it is harder than using -wave, which won't really do the job correctly, since -wave will distort the top of the image as well as the bottom.

So you need to compute a sine wave from -function sinusoid and convert that into x,y coordinates with txt: format output. Then draw a black polygon on a white background, floodfill with transparency and put that image into the alpha channel of the input image using -compose copy_opacity -composite. Then save the result as png.

Input:
Image

Code: Select all

infile="lena.jpg"
amplitude=10     # amplitude in pixels of the sine curve
row=128            # row in image for the center line of the sine curve 
ww=`convert -ping "$infile" -format "%w" info:`
hh=`convert -ping "$infile" -format "%h" info:`
wm1=$((ww-1))
hm1=$((hh-1))
qrange=`convert xc: -format "%[fx:quantumrange]" info:`
amp=`convert xc: -format "%[fx:$amplitude/$qrange]" info:`
off=`convert xc: -format "%[fx:$row/$qrange]" info:`
coords=`convert -size 1x256 gradient: -rotate 90 -function sinusoid "1,180,$amp,$off" txt:- |\
sed -n 's/^\([^,]*\),.*: [(]\([^,]*\).*$/\1,\2/p'`
coords="$coords $wm1,$hm1 0,$hm1"
convert "$infile" \
\( +clone -fill white -colorize 100 -fill black -draw "polygon $coords" -alpha off \) \
-compose copy_opacity -composite lena_sine_crop.png
Image


See
http://www.imagemagick.org/Usage/transf ... n_sinusoid
http://www.imagemagick.org/Usage/files/#txt
http://www.imagemagick.org/Usage/draw/#matte
http://www.imagemagick.org/Usage/basics/#parenthesis
http://www.imagemagick.org/Usage/basics/#clone
http://www.imagemagick.org/Usage/compose/#compose
http://www.imagemagick.org/Usage/compose/#copyopacity

Re: Cut/crop sine wave shape into image?

Posted: 2015-12-04T19:53:46-07:00
by fmw42
This should be a bit smoother by computing floating point y-coordinates.

Code: Select all

infile="lena.jpg"
amplitude=10
row=128
ww=`convert -ping "$infile" -format "%w" info:`
hh=`convert -ping "$infile" -format "%h" info:`
wm1=$((ww-1))
hm1=$((hh-1))
qrange=`convert xc: -format "%[fx:quantumrange]" info:`
amp=`convert xc: -format "%[fx:$amplitude/$qrange]" info:`
off=`convert xc: -format "%[fx:$row/$qrange]" info:`
coords=`convert -size 1x256 gradient: -rotate 90 -function sinusoid "1,180,0.5,0.5" txt:- |\
sed -n 's/^\([^,]*\),.*: [(]\([^,]*\).*$/\1,\2/p'`
xArr=(`echo "$coords" | cut -d, -f1`)
yArr=(`echo "$coords" | cut -d, -f2`)
len=${#xArr[*]}
#echo "len=$len;"
#echo "${xArr[*]}
#echo "${yArr[*]}
for ((i=0; i<len; i++)); do
yy=`echo "scale=6; $amplitude*${yArr[$i]}*2/$qrange+$row" | bc`
coordArr[$i]="${xArr[$i]},$yy"
done
coords="${coordArr[*]} $wm1,$hm1 0,$hm1"
convert "$infile" \
\( +clone -fill white -colorize 100 -fill black -draw "polygon $coords" -alpha off \) \
-compose copy_opacity -composite lena_sine_crop2.png
Image

Re: Cut/crop sine wave shape into image?

Posted: 2015-12-07T10:47:49-07:00
by oeoeo
Thanks! I'll poke around with that. Much appreciated.

And just for the record, here's the version info:
Version: ImageMagick 6.9.1-4 Q16 x86_64 2015-06-02 http://www.imagemagick.org
Copyright: Copyright (C) 1999-2015 ImageMagick Studio LLC
License: http://www.imagemagick.org/script/license.php
Features: Cipher DPC Modules OpenMP
Delegates (built-in): bzlib cairo djvu fftw fontconfig freetype jng jpeg lcms ltdl openexr pangocairo png rsvg tiff webp wmf x xml zlib

Re: Cut/crop sine wave shape into image?

Posted: 2015-12-07T13:24:44-07:00
by oeoeo
Hmmm...I'm running this as a bash script (which may or may not be the correct thing to do) from a dir with "lena.jpg" at the same level as the script (which I'm calling 'thing.sh').

So I do this:

Code: Select all

me@place$ ./thing.sh
...and I get a multitude of these messages:

Code: Select all

 (standard_in) 1: syntax error
 (standard_in) 1: syntax error
 (standard_in) 1: syntax error
 (standard_in) 1: syntax error
 etc....
 
The image created is also incorrect (i.e. no sine wave, etc.).

Thanks!

Re: Cut/crop sine wave shape into image?

Posted: 2015-12-07T15:24:26-07:00
by fmw42
If you have made it a proper bash shell script, it needs to have

Code: Select all

#!/bin/bash
as the first line. Then you need to make the script executable by typing in a terminal window

Code: Select all

chmod u+x thing.sh
Then to run it, you will need to type in a terminal window

Code: Select all

bash ./thing.sh

Re: Cut/crop sine wave shape into image?

Posted: 2015-12-07T15:39:26-07:00
by oeoeo
Yep. Did that. Thanks though.

Actually stepped through it with someone with MUCH more bash scripting experience than me and got it to work.

Needed a couple changes but so far so good.

For those playing along at home, this is what it took:

Code: Select all

#1/bin/bash
infile="lena.jpg"
amplitude=10
row=128
ww=`convert -ping "$infile" -format "%w" info:`
hh=`convert -ping "$infile" -format "%h" info:`
wm1=$((ww-1))
hm1=$((hh-1))
coords=`convert -size 1x256 gradient: -rotate 90 -function sinusoid "1,180,0.5,0.5" txt:- |\
sed -n 's/^\([^,]*\),.*: [(]\([^,]*\).*$/\1,\2/p'`
#echo $coords
xArr=(`echo "$coords" | cut -d, -f1`)
yArr=(`echo "$coords" | cut -d, -f2`)
len=${#xArr[*]}

for ((i=0; i<len; i++))
do
  y="${yArr[$i]}"
  yy=$(echo "scale=6; $amplitude*${y%%%}*.01*2+$row")
  yy=$(echo "${yy}" | bc)
#  yy=`echo "scale=6; $amplitude*${yArr[$i]}*2/$qrange+$row" | bc`
  coordArr[$i]="${xArr[$i]},$yy"
done

coords="${coordArr[*]} $wm1,$hm1 0,$hm1"
echo $coords
convert "$infile" \( +clone -fill white -colorize 100 -fill black -draw "polygon $coords" -alpha off \) -compose copy_opacity -composite lena_sine_crop2.png
qrange was throwing us. As well as the % sign being piped into bc.

Re: Cut/crop sine wave shape into image?

Posted: 2015-12-07T15:44:45-07:00
by oeoeo
Oddly enough, it looks like there are 2 pixels not getting nuked.

See them on the far left hand side under wave?

Image

I'll try to debug a bit but perhaps it's obvious within the coords??

Thanks again!

Re: Cut/crop sine wave shape into image?

Posted: 2015-12-07T15:50:31-07:00
by fmw42
I will check on that. Likely a draw floodfill issue. I will get back.

Also note:
#1/bin/bash
This should be

#!/bin/bash

exclamation, not the numeral 1.

I do not see a % sign being piped into bc in my code?

Re: Cut/crop sine wave shape into image?

Posted: 2015-12-07T16:07:04-07:00
by oeoeo
ha! oops. yeah, good catch!

Re: Cut/crop sine wave shape into image?

Posted: 2015-12-07T16:10:58-07:00
by fmw42
There appears to be a bug in -draw polygon when creating the alpha channel mask image. I get one bad white pixel at 0,149. But if I draw it the other way (white on a black background), it works fine for me. Try

Code: Select all

infile="lena.jpg"
amplitude=10
row=128
ww=`convert -ping "$infile" -format "%w" info:`
hh=`convert -ping "$infile" -format "%h" info:`
wm1=$((ww-1))
hm1=$((hh-1))
qrange=`convert xc: -format "%[fx:quantumrange]" info:`
amp=`convert xc: -format "%[fx:$amplitude/$qrange]" info:`
off=`convert xc: -format "%[fx:$row/$qrange]" info:`
coords=`convert -size 1x256 gradient: -rotate 90 -function sinusoid "1,180,0.5,0.5" txt:- |\
sed -n 's/^\([^,]*\),.*: [(]\([^,]*\).*$/\1,\2/p'`
xArr=(`echo "$coords" | cut -d, -f1`)
yArr=(`echo "$coords" | cut -d, -f2`)
len=${#xArr[*]}
#echo "len=$len;"
#echo "${xArr[*]}
#echo "${yArr[*]}
for ((i=0; i<len; i++)); do
yy=`echo "scale=6; $amplitude*${yArr[$i]}*2/$qrange+$row" | bc`
coordArr[$i]="${xArr[$i]},$yy"
done
coords="$wm1,0 0,0 ${coordArr[*]}"
convert "$infile" \
\( +clone -fill black -colorize 100 -fill white -draw "polygon $coords" -alpha off \) \
-compose copy_opacity -composite lena_sine_crop3.png

Re: Cut/crop sine wave shape into image?

Posted: 2015-12-07T16:18:38-07:00
by oeoeo
Weird. When I run your code, I get a bunch of the aforementioned "(standard in) 1: syntax error" messages (one for each set of coords, I'm guessing??)

...and then the output image looks like this:
Image

Re: Cut/crop sine wave shape into image?

Posted: 2015-12-07T16:22:43-07:00
by fmw42
It works fine for me. See viewtopic.php?f=3&t=28790. What is your exact command file code and did you make the adjustments as I mentioned before. Check for copy and paste errors to be sure there are no line ending issues.

Re: Cut/crop sine wave shape into image?

Posted: 2015-12-07T16:35:29-07:00
by oeoeo
ImageMagick Version

Code: Select all

Version: ImageMagick 6.9.1-4 Q16 x86_64 2015-06-02 http://www.imagemagick.org
Copyright: Copyright (C) 1999-2015 ImageMagick Studio LLC
License: http://www.imagemagick.org/script/license.php
Features: Cipher DPC Modules OpenMP
Delegates (built-in): bzlib cairo djvu fftw fontconfig freetype jng jpeg lcms ltdl openexr pangocairo png rsvg tiff webp wmf x xml zlib
Server Info (FWIW):

Code: Select all

cat /proc/version
Linux version 2.6.32-504.8.1.el6.x86_64 (mockbuild@c6b9.bsys.dev.centos.org) (gcc version 4.4.7 20120313 (Red Hat 4.4.7-11) (GCC) ) #1 SMP Wed Jan 28 21:11:36 UTC 2015
This is what works for me:

Code: Select all

#!/bin/bash
infile="lena.jpg"
amplitude=10
row=128
ww=`convert -ping "$infile" -format "%w" info:`
hh=`convert -ping "$infile" -format "%h" info:`
wm1=$((ww-1))
hm1=$((hh-1))
coords=`convert -size 1x256 gradient: -rotate 90 -function sinusoid "1,180,0.5,0.5" txt:- |\
sed -n 's/^\([^,]*\),.*: [(]\([^,]*\).*$/\1,\2/p'`
#echo $coords
xArr=(`echo "$coords" | cut -d, -f1`)
yArr=(`echo "$coords" | cut -d, -f2`)
len=${#xArr[*]}

for ((i=0; i<len; i++))
do
  y="${yArr[$i]}"
  yy=$(echo "scale=6; $amplitude*${y%%%}*.01*2+$row")
  yy=$(echo "${yy}" | bc)
#  yy=`echo "scale=6; $amplitude*${yArr[$i]}*2/$qrange+$row" | bc`
  coordArr[$i]="${xArr[$i]},$yy"
done

coords="${coordArr[*]} $wm1,$hm1 0,$hm1"
echo $coords
convert "$infile" \( +clone -fill white -colorize 100 -fill black -draw "polygon $coords" -alpha off \) -compose copy_opacity -composite lena_sine_crop2.png

Re: Cut/crop sine wave shape into image?

Posted: 2015-12-07T16:38:00-07:00
by fmw42
Your changes do not make sense to me. But if it works, fine.
y="${yArr[$i]}"
yy=$(echo "scale=6; $amplitude*${y%%%}*.01*2+$row")
yy=$(echo "${yy}" | bc)
# yy=`echo "scale=6; $amplitude*${yArr[$i]}*2/$qrange+$row" | bc`

Did you try just:

Code: Select all

yy=$(echo "scale=6; $amplitude*${yArr[$i]}*2/$qrange+$row" | bc)
or

Code: Select all

y=${yArr[$i]}
yy=$(echo "scale=6; $amplitude*$y*2/$qrange+$row" | bc)

.01 is not the same as 1/$qrange = 1/65535 = 0.000015259021897 for Q16 IM


Out of curiosity, why do you want to do this? What is your final goal?