I want to change the text on gif, change "YOU" to other words, but I do not know how to do it .
source gif
Here is some unix bash code using Imagemagick to do what you want. Note that you did not clean out all the old text completely from your head image and so near about frame 35, there is still a "y" showing.
Input:
What I did was measure a rectangular region in the top part of the head to restrict where the text was drawn. I correct that region by the width and height of the text you want to draw. Then I loop over each of the 45 frames and compute 30 random values for each of the pointsize (between 5 and 18), the x-position and the y-position within the bounds of the box. I save a list of accumulated values to use with the -annotate function to draw the text in the frame. Once I have all frames drawn with random values for the text, I create the final animation.
cd
cd desktop/test
text="test"
wd=180
ht=110
xo=100
yo=60
minsize=5
maxsize=18
dims=`convert -pointsize $maxsize label:"$text" -format "%#" info:`
WxH=`echo $dims | cut -d+ -f1`
twidth=`echo $WxH | cut -dx -f1`
theight=`echo $WxH | cut -dx -f2`
ww=$((wd-twidth))
hh=$((ht-theight))
diffsize=$((maxsize-minsize))
numtext=30
for ((j=0; j<45; j++)); do
list=""
jj=`printf "%02d" $j`
echo "$j"
convert head.gif[$j] -background black -flatten tmp$jj.gif
for ((i=0; i<numtext; i++)); do
psize=`convert xc: -format "%[fx:round($minsize+$diffsize*random())]" info:`
xoff=`convert xc: -format "%[fx:round($xo+$ww*random())]" info:`
yoff=`convert xc: -format "%[fx:round($yo+$hh*random())]" info:`
list="$list -pointsize $psize -annotate +${xoff}+${yoff} '$text'"
done
convert tmp$jj.gif -font arial -fill white $list tmp$jj.gif
done
convert -delay 20 tmp*.gif -loop 0 head_test.gif
rm -f tmp*.gif
cd
If you want the text rotated, then modify the -annotate arguments as follows. Here I rotate -10 degrees counter clockwise, but for annotate, I need to use the equivalent positive rotations, so 350 degrees.
cd
cd desktop/test
text="test"
wd=180
ht=110
xo=100
yo=60
minsize=5
maxsize=18
dims=`convert -pointsize $maxsize label:$text -format "%#" info:`
WxH=`echo $dims | cut -d+ -f1`
twidth=`echo $WxH | cut -dx -f1`
theight=`echo $WxH | cut -dx -f2`
ww=$((wd-twidth))
hh=$((ht-theight))
diffsize=$((maxsize-minsize))
numtext=30
for ((j=0; j<45; j++)); do
list=""
jj=`printf "%02d" $j`
echo "$j"
convert head.gif[$j] -background black -flatten tmp$jj.gif
for ((i=0; i<numtext; i++)); do
psize=`convert xc: -format "%[fx:round($minsize+$diffsize*random())]" info:`
xoff=`convert xc: -format "%[fx:round($xo+$ww*random())]" info:`
yoff=`convert xc: -format "%[fx:round($yo+$hh*random())]" info:`
list="$list -pointsize $psize -annotate 350x350+${xoff}+${yoff} '$text'"
done
convert tmp$jj.gif -font arial -fill white $list tmp$jj.gif
done
convert -delay 20 tmp*.gif -loop 0 head_test.gif
rm -f tmp*.gif
cd
Related
History: I try to apply a watermark on a series of images in a directory, at linux, putting that watemark on an extra created space / border below the image. Both Watermark and the extra space is resized / created depending on the height size on the image they are applied.
I do various calculations based on the height of the image that is processed each time that they are saved on some variables. However, I do not know how to a) Make a script to be applied to all the images on the directory, using the saved height calculations PER IMAGE, OR b) to be applied these calculations PER IMAGE, as "single terminal command" e.g. "for pic in DSC*.*; do height calculations....... and saved at that variable to be used for the next batch terminal command"
The variables of imagemagick. How I saved them to be used for the next use, per image?
height=`convert DSC__12.jpg -format "%w" info:`
yoff_p50=`convert xc: -format "%[fx:$height/50]" info:`
yoff_p100=`convert xc: -format "%[fx:$height/100]" info:`
yoff_p200=`convert xc: -format "%[fx:$height/200]" info:`
I tried the following linux terminal command: Is there a better elegant (shorter?) way?
for pic in DSC*.*;
do height=`convert "$pic" -format "%w" info:`;
yoff_p50=`convert xc: -format "%[fx:$height/50]" info:`;
yoff_p100=`convert xc: -format "%[fx:$height/100]" info:`;
yoff_p200=`convert xc: -format "%[fx:$height/200]" info:`;
convert -background black -gravity NorthWest -extent 0%x0%+0+${yoff_p50} -pointsize ${yoff_p100} -fill white -undercolor '#00000080' -gravity SouthWest -annotate +${yoff_p100}+${yoff_p200} "$(stat -c '%y' "$pic")" "$pic" "${pic//.*}-d.jpg";
done;
for pic in DSC*-d.*;
do height=`convert "$pic" -format "%w" info:`;
yoff_p50=`convert xc: -format "%[fx:$height/50]" info:`;
yoff_p100=`convert xc: -format "%[fx:$height/100]" info:`;
yoff_p200=`convert xc: -format "%[fx:$height/200]" info:`;
convert /home/elias/Data/PHOTOS/watermark_0.png -resize ${yoff_p50}x${yoff_p50}^ /home/elias/Data/PHOTOS/res_watermark_0.png;
composite -dissolve 100% -gravity SouthEast /home/elias/Data/PHOTOS/res_watermark_0.png "$pic" "${pic//.*}-marked.jpg";
done;
ps. How I can check what values are saved per imagemagick variable?
i found out how to check the variable value in linux terminal: echo ${height}
UPDATE: Solution: The solution by Mark Setchell worked.
Finally, i run: ..and it did the job from linux terminal very fine.
for pic in DSC*.* ; do
#Save either the date of File Creation or Modification on filename
exiftool "-FileName<CreateDate" -d "${pic//.*}_%Y%m%d_%H%M%S.jpg" "$pic" && exiftool "-FileName<FileModifyDate" -d "${pic//.*}_%Y%m%d_%H%M%S.jpg" "$pic" ;
done;
for pic in DSC*.* ; do
# Determine offsets and sizes
read w y1 y2 y3 < <(identify -format "%w %[fx:w/50] %[fx:w/100] %[fx:w/200]" "$pic");
ts=$(stat -c '%y' "$pic");
convert -size ${w}x${y1} xc:black -gravity SouthWest \
-pointsize ${y2} -fill white -undercolor '#00000080' -annotate +${y2}+${y3} "$ts" \
\( /home/elias/Data/PHOTOS/res_watermark_0.png -resize "${y1}x${y1}^" \) -gravity East -composite \
"$pic" +swap -append "${pic//.*}-marked.jpg";
done
It can probably be improved further, but I would go with something more like this:
#!/bin/bash
for f in DSC* ; do
# Determine offsets and sizes
read w y1 y2 y3 < <(identify -format "%w %[fx:w/50] %[fx:w/100] %[fx:w/200]" "$f")
# Get timestamp - different on macOS. You want: ts=$(stat -c '%y' "$f")
ts=$(stat -f "%Sm%n" "$f")
convert -size ${w}x${y1} xc:black -gravity SouthWest \
-pointsize ${y2} -fill white -undercolor '#00000080' -annotate +${y2}+${y3} "$ts" \
\( watermark.png -resize "${y1}x${y1}^" \) -gravity East -composite \
"$f" +swap -append watermarked-"$f".jpg
done
Things to note:
The line beginning read w y1... gets all the calculated values in a single go - this will be quicker.
The line beginning ts=$(...) gets the timestamp. I abstracted it out because I am on macOS and it is different. You can re-integrate it, if you want.
The final line is where the action is. I create a black annotation bar the right size first, then write in the timestamp in white on the left. Then, on the next line I load the watermark and resize it and splat it into the right corner of the black annotation bar. Then, on the next line, I load the main image, and swap the order so the annotation bar is at the bottom and the image is at the top before appending.
Remember when debugging ImageMagick scripts, you can add in -write "debug.png" at any position to see how something looks after resizing , or before compositing or wherever.
Another way to save variables in one ImageMagick command is using declare.
declare `convert xc: -format "yoff_p50=%[fx:$height/50]\nyoff_p100=%[fx:$height/50]\nyoff_p200=%[fx:$height/200]\n" info:`
Example:
declare `convert rose: -format "ww=%[fx:w]\nhh=%[fx:h]\n" info:` echo "ww=$ww; hh=$hh;"
ww=70; hh=46;
I want to split an image on the basis of color of the line.
I'm using hough line detector to detect a line and mark it with red color.
Now,i want to split the image on the basis of line which has been overlayed using line detection algorithm.
Image with line detection overlay
i want to split the above image into two.
You can do that in Imagemagick with some Unix shell commands as follows. The basic idea is to average the image to one column, then search the column for the y coordinate of the red pixel. Then use that to crop the image into two parts.
INPUT:
width=$(convert -ping tRbWW.png -format "%w" info:)
height=$(convert -ping tRbWW.png -format "%h" info:)
y=$(convert tRbWW.png -alpha off -scale 1x! -fuzz 20% -fill red -opaque red txt:- | grep "red" | head -n 1 | cut -d: -f1 | cut -d, -f2)
height1=$((y+1))
height2=$((height-y+1))
convert tRbWW.png \
\( -clone 0 -gravity north -crop ${width}x${height1}+0+0 +repage +write top.png \) \
\( -clone 0 -gravity south -crop ${width}x${height2}+0+0 +repage +write bottom.png \) \
null:
Top:
Bottom:
Given an animated gif over a solid background color
I'd like to trim away the padding. Concretely, I'd like to crop the image to the maximum extent of the foreground object over all frames:
I can't seem to find the right combination of -alpha, -background to achieve this with a single convert command. For example, if I issue
convert -dispose 2 input.gif -trim -layers TrimBounds fail.gif
I get random "background" colors for frames whose individual trimmed extents are smaller than the maximum extent over all frames:
I can achieve the correct output with a long string of commands:
convert input.gif -trim -layers TrimBounds out-%03d.miff
mogrify -background "rgb(20%,30%,80%)" -layers flatten out-*.miff
convert out-*.miff output.gif
rm out-*.miff
This is slow, writes a bunch of temporary files, and requires me to know the background color ("rgb(20%,30%,80%)") explicitly.
Is there a simpler way to trim an animated gif?
This related question considers explicit cropping rather than automatic trimming.
Finally, this seems to work in ImageMagick with one line to get the background color and one line of processing. No temp files are needed.
bgcolor=`convert input.gif[0] -format "%[pixel:u.p{0,0}]" info:`
convert -dispose previous -delay 10 -background "$bgcolor" input.gif -trim -layers TrimBounds -coalesce -layers optimize -loop 0 output.gif
You can accomplish this sort of trimming using IM's "-distort" with a defined viewport.
convert oHBWq.gif -coalesce +repage -background none \
\( -clone 0--1 -trim -flatten -trim \) \
-set option:distort:viewport %[fx:u[-1].w]x%[fx:u[-1].h]+%[fx:u[-1].page.x]+%[fx:u[-1].page.y] \
-delete -1 -distort SRT 0 +repage output.gif
That clones the input frames, trims them individually, and flattens them keeping their original alignment. Then it trims that flattened one again to get rid of the excess transparent background. The result will be the right size and have the correct page offsets for the finished images. You don't have to know the background color.
Now you can easily get those dimensions and offsets into a distort viewport setting and do a no-op distort. Delete the cloned flattened one that was used to get the measurements, "+repage" the rest, and finish with whatever other GIF settings you need.
This is an interesting question. At the moment, I do not see how to improve it so that extra file(s) are not needed. But I will consider it further. But I can clean your code up a bit and make it easier for you and make the output.gif look correct.
bgcolor=`convert oHBWq.gif[0] -format "%[pixel:u.p{0,0}]" info:`
convert oHBWq.gif -trim -layers TrimBounds out-%03d.miff
mogrify -background "$bgcolor" -layers flatten out-*.miff
convert -dispose previous -delay 10 out-*.miff -loop 0 output.gif
rm out-*.miff
This does the same thing as above, but only requires saving 1 multi-frame miff file. The subshell loop processing does similar to your mogrify.
bgcolor=`convert oHBWq.gif[0] -format "%[pixel:u.p{0,0}]" info:`
num=`convert oHBWq.gif -format "%n\n" info: | head -n 1`
convert oHBWq.gif -trim -layers TrimBounds tmp.miff
(for ((i=0; i<num; i++)); do
convert tmp.miff[$i] -background "$bgcolor" -layers flatten miff:-
done ) |\
convert -dispose previous -delay 10 - -loop 0 output2.gif
rm tmp.miff
This also works without having to save any temp files, but is has to repeat the -trim -layers trim bounds for each loop iteration.
bgcolor=`convert oHBWq.gif[0] -format "%[pixel:u.p{0,0}]" info:`
num=`convert oHBWq.gif -format "%n\n" info: | head -n 1`
echo "num=$num"
(for ((i=0; i<num; i++)); do
convert oHBWq.gif -trim -layers TrimBounds miff:- |\
convert -[$i] -background "$bgcolor" -layers flatten miff:-
done ) |\
convert -dispose previous -delay 10 - -loop 0 output3.gif
This is close but for one frame:
bgcolor=`convert oHBWq.gif[0] -format "%[pixel:u.p{0,0}]" info:`
convert -dispose previous -delay 10 oHBWq.gif -trim -layers TrimBounds -background "$bgcolor" -layers optimize -loop 0 output5.gif
I have ~200 scanned photos which I want to crop the white space out of. See example:
Can someone provide me with the appropriate command line code to do this?... I have been trying to sort out the -trim and -fuzz options with no luck. NOT ALL images are same size (i.e. 4x6, 5x7, etc). All images were scanned/saved as jpg
Ideal scenario is a script where new trimmed photos are saved in one subdirectory.
Thanks in advance!
I would suggest using -morphology to remove the scan artifacts, trim, and then capture the resulting paging.
PAGE_OFFSET=$(convert TrmkF.jpg -morphology Dilate:3 Diamond:3,5 -fuzz 10% -trim -format '%wx%h%O' info:-)
The $PAGE_OFFSET variable should now have the rough location of the scanned photo. We can apply that value with the -crop command.
convert TrmkF.jpg -crop $PAGE_OFFSET output.jpg
[![output][1]][1]
Edit
A (powershell) batch script may look as simple as...
Get-ChildItem "C:\path\to\photos" -Filter *.jpg |
Foreach-Object {
$pageOffset = magick $_.FullName -morphology Dilate:3 Diamond:3,5 -fuzz 10% -trim -format '%xx%h%O' info:- | Out-String
$output = $_.FullName + ".output.jpg"
magick $_.FullName -crop $pageOffset +repage $output
}
ymmv
[1]: https://i.stack.imgur.com/u8bSs.png
I've found that the above gives bad results, I think the formatting is different on MacOS or something so sharing the success story here. I have exactly this same issue - hundreds of scanned photos with some blotches in the white ruining the auto trim function.
I just modified parameters from the other individual's answer and got amazing results using this:
cd into your folder of images
mkdir ../done
v
echo "$f";\
size=$(magick "$f" -bordercolor White -border 10x10 \
-morphology Dilate:5 Diamond:5,7 -fuzz 5% -trim \
-format "%wx%h%O" info:-); \
echo $size; \
magick "$f" -bordercolor White -border 10x10 -crop $size +repage "../done/$f"; done;
im getting the most existing colors of an image and display it with the "histogram" funktion like
convert image.jpg -scale 100x100 -gravity \
center -crop 50% -dither None -remap color_map.gif \
-format %c histogram:info:
22: ( 0, 0, 0) #000000 black
881: (119,133,142) #77858E rgb(119,133,142)
268: (186, 84, 29) #BA541D rgb(186,84,29)
662: (212,212,212) #D4D4D4 grey83
20: (244,203, 98) #F4CB62 rgb(244,203,98)
647: (255,255,255) #FFFFFF white
Ho can i work now with this output? i want to save the most existing color in my database, but i dont know how to get now only the color with the number 881.
Can any one help me?
If you want to do this purely from the shell (assuming Bash-like Unix environment), something like this would work:
convert image.jpg -scale 100x100 -gravity center \
-crop 50% -dither None -remap color_map.gif \
-format %c histogram:info: | sort | tail -n1 | \
sed -e 's/.*\(#[0-9A-F]\+\).*/\1/'
That takes the output from ImageMagick, sorts it so the largest color count is on the bottom, takes just that line, then extracts the color hex from the line. You can tweak the sed regex if your goal is to get the decimal rgb values instead of the hex.
So for your example image, the output should be just:
#77858E