Cut/crop sine wave shape into image?

Questions and postings pertaining to the usage of ImageMagick regardless of the interface. This includes the command-line utilities, as well as the C and C++ APIs. Usage questions are like "How do I use ImageMagick to create drop shadows?".
oeoeo
Posts: 10
Joined: 2015-12-04T17:36:18-07:00
Authentication code: 1151

Cut/crop sine wave shape into image?

Post 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.
User avatar
fmw42
Posts: 25562
Joined: 2007-07-02T17:14:51-07:00
Authentication code: 1152
Location: Sunnyvale, California, USA

Re: Cut/crop sine wave shape into image?

Post 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
User avatar
fmw42
Posts: 25562
Joined: 2007-07-02T17:14:51-07:00
Authentication code: 1152
Location: Sunnyvale, California, USA

Re: Cut/crop sine wave shape into image?

Post 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
oeoeo
Posts: 10
Joined: 2015-12-04T17:36:18-07:00
Authentication code: 1151

Re: Cut/crop sine wave shape into image?

Post 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
oeoeo
Posts: 10
Joined: 2015-12-04T17:36:18-07:00
Authentication code: 1151

Re: Cut/crop sine wave shape into image?

Post 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!
User avatar
fmw42
Posts: 25562
Joined: 2007-07-02T17:14:51-07:00
Authentication code: 1152
Location: Sunnyvale, California, USA

Re: Cut/crop sine wave shape into image?

Post 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
oeoeo
Posts: 10
Joined: 2015-12-04T17:36:18-07:00
Authentication code: 1151

Re: Cut/crop sine wave shape into image?

Post 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.
oeoeo
Posts: 10
Joined: 2015-12-04T17:36:18-07:00
Authentication code: 1151

Re: Cut/crop sine wave shape into image?

Post 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!
User avatar
fmw42
Posts: 25562
Joined: 2007-07-02T17:14:51-07:00
Authentication code: 1152
Location: Sunnyvale, California, USA

Re: Cut/crop sine wave shape into image?

Post 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?
oeoeo
Posts: 10
Joined: 2015-12-04T17:36:18-07:00
Authentication code: 1151

Re: Cut/crop sine wave shape into image?

Post by oeoeo »

ha! oops. yeah, good catch!
User avatar
fmw42
Posts: 25562
Joined: 2007-07-02T17:14:51-07:00
Authentication code: 1152
Location: Sunnyvale, California, USA

Re: Cut/crop sine wave shape into image?

Post 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
oeoeo
Posts: 10
Joined: 2015-12-04T17:36:18-07:00
Authentication code: 1151

Re: Cut/crop sine wave shape into image?

Post 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
User avatar
fmw42
Posts: 25562
Joined: 2007-07-02T17:14:51-07:00
Authentication code: 1152
Location: Sunnyvale, California, USA

Re: Cut/crop sine wave shape into image?

Post 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.
oeoeo
Posts: 10
Joined: 2015-12-04T17:36:18-07:00
Authentication code: 1151

Re: Cut/crop sine wave shape into image?

Post 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
User avatar
fmw42
Posts: 25562
Joined: 2007-07-02T17:14:51-07:00
Authentication code: 1152
Location: Sunnyvale, California, USA

Re: Cut/crop sine wave shape into image?

Post 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?
Post Reply