Is there a simple way to extract EXIF data as text from an image file using ImageMagick. Something like the way to do it for IPTC data:
convert input.jpeg data.iptc <= binary data
convert input.jpeg data.iptctext <= textual data
Sadly this doesn't work for EXIF data:
convert input.jpeg data.exif <= binary data
convert input.jpeg data.exiftext <= not working
I know that i can use
identify -verbose input.jpeg
but then i would have to parse the result in order to search for all the EXIF and IPTC data.
So is there a simple way to do it with pure ImageMagick?
Like this:
identify -format '%[EXIF:*]' image.jpg
Output:
exif:ApertureValue=4845/1918
exif:BrightnessValue=4991/792
exif:ColorSpace=1
exif:ComponentsConfiguration=1, 2, 3, 0
exif:Compression=6
exif:DateTime=2014:08:31 14:18:07
exif:DateTimeDigitized=2014:08:31 14:18:07
exif:DateTimeOriginal=2014:08:31 14:18:07
exif:ExifImageLength=2448
exif:ExifImageWidth=3264
exif:ExifOffset=204
exif:ExifVersion=48, 50, 50, 49
...
...
Related
I am trying to convert a set of raw video frames from YUV444 to sRGB using ImageMagick.
Input format: Raw YUV444 limited range, BT.709 in planar data order.
Required output format: sRGB (set of PNG images).
Main issue: ImageMagick conversion always applies JPEG conversion formula.
Remark about "limited range" YUV format:
In 8 bits limited range YUV format, the range of Y is [16, 235] and the range of U, V is [16, 240]. (limited range BT.709 is used in HTDV systems).
JPEG uses "full range" YUV format, where Y,U,V range is [0, 255].
sRGB is used in PC systems, and the range of R,G,B is full range [0, 255].
YUV and YCbCr are interchangeable.
For testing, I used the following sample image:
Sample image in sRGB format (rgb_input.png):
I converted the sample to YUV444 format using FFmpeg:
ffmpeg -y -colorspace bt709 -i rgb_input.png -pix_fmt yuv444p yuv_input.yuv
Following image illustrates the YUV444 output (in planar data order):
Input image for ImageMagick in YUV444 format (yuv_input.yuv planar data order illustration):
I converted yuv_input.yuv to PNG using ImageMagick converter (version 7.0.8-51):
magick -depth 8 -interlace plane -size 128x96 -colorspace Rec709YCbCr -sampling-factor 4:4:4 yuv:yuv_input.yuv rgb_output_magick.png
Result of ImageMagick (rgb_output_magick.png):
If you look carefully you see that the image is different than rgb_input.png.
Same conversion using FFmpeg (used as reference):
ffmpeg -y -s 128x96 -colorspace bt709 -pix_fmt yuv444p -i yuv_input.yuv -pix_fmt rgb24 rgb_output_ffmpeg.png
Result of FFmpeg (rgb_output_ffmpeg.png):
Note: The true format of my raw input video frames prevents me from using FFmpeg.
Conversion formula from 8 bits limited range YUV BT.709 to sRGB:
R = 1.1644*Y + 0.00000*U + 1.79270*V - 248.10
G = 1.1644*Y - 0.21325*U - 0.53291*V + 76.878
B = 1.1644*Y + 2.11240*U + 0.00000*V - 289.02
How can I do the above conversion using ImageMagick converter?
As you requested, this would be the ImageMagick color-matrix command for your transform, assuming it makes sense. ImageMagick color-matrix values are normalized to the range 0 to 1, including the offset (right-most) term. I assume your offsets are in the range 0 to 255 (8-bit). So I am not sure if this even makes sense. Nevertheless, here is the way it would look.
magick input -color-matrix \
"1.1644 0.00000 1.79270 0, 0, -0.9729 \
1.1644 -0.21325 -0.53291 0, 0, 0.30148 \
1.1644 2.11240 0.00000 0, 0, -1.1334 \
0 0 0 1, 0, 0 \
0 0 0 0, 1, 0 \
0 0 0 0, 0, 1" output
See http://www.adobetutorialz.com/articles/1987/1/Color-Matrix
I am using Imagemagick in order to get the perceptual hash of an image. I use the following command:
identify -verbose -define identify:moments x.png
The output returns amongst other params also the pereceptual hash:
I1: 0.0017694 (0.451197) I2: 3.22345e-07 (0.0209605) I3: 2.88038e-10 (0.00477606) I4: 3.93968e-12 (6.53253e-05) I5: 1.2326e-22 (3.38892e-08) I6: -1.94034e-15 (-8.20426e-06) I7: -4.91938e-23 (-1.35254e-08) I8: 5.56374e-16 (2.35249e-06) Channel perceptual hash: Red, Hue: PH1: 0.407586, 0.690687 PH2: 1.88394, 2.91999 PH3: 2.36028, 3.96979 PH4: 5.36184, 5.3591 PH5: 9.25849, 11 PH6: 6.30422, 6.93025 PH7: 9.6332, 10.0241 Green, Chroma: PH1: 0.293148, -0.0406998 PH2: 1.49146, 2.52843 PH3: 2.21568, 0.992456 PH4: 3.52683, 2.3777 PH5: 6.48291, 4.06334 PH6: 4.38149, 4.23342 PH7: 6.64322, 5.35487 Blue, Luma: PH1: 0.329865, 0.33357 PH2: 1.6461, 1.63528 PH3: 2.39206, 2.26483 PH4: 3.72747, 4.09284 PH5: 6.789, 7.36151 PH6: 4.56493, 5.0171 PH7: 7.83416, 7.50669
I want to save the hash and then compute the distance between 2 images. How can I convert the above output to a hash and calculate the distance between 2 hashes?
See http://www.fmwconcepts.com/misc_tests/perceptual_hash_test_results_510/index.html for detailed information and tests of this perceptual hash.
Basically it creates 42 floating point values that need to be compared with another set of 42 floating point values from another image using Sum Squared metric.
This is not a simple binary hash that can be easily stored as a string of 1s and 0x and compared using the Hamming distance.
But you can compare two images from their perceptual hashes in ImageMagick using
compare -metric phash image1 image2 null:
You can output the phash values to a .json file if you want.
Alternately, I have two bash unix ImageMagick shell scripts (phashconvert and phashcompare). One will convert the 42 floats to a string of digits that can be saved in the file in the comment section. The second will read two file's comment sections to extract the string, convert them back to floats and then use the Sum Squared Metric to evaluate them. But note this process is only an approximation due to the conversion back and forth from floats to digits.
If you just want to extract the 42 floats, this should do it (from my script phashconvert)
identify -quiet -verbose -moments -alpha off "x.png" | grep "PH[1-7]" | sed -n 's/.*: \(.*\)$/\1/p' | sed 's/ *//g' | tr "," "\n"
I'm trying to convert a 16 bit greyscale PNG to a raw file. The image size is 640*480.
First, identify:
$ identify image.png
image.png PNG 640x480 640x480+0+0 16-bit PseudoClass 65536c 299KB 0.000u 0:00.000
I'm expecting the result file to be 640*480*2 bytes in size.
Attempt 1:
$ convert image.png -depth 16 image.raw
This gives a file size of 330805 bytes. Its first 16 bytes look like:
0x00000000: 89504E47 0D0A1A0A 0000000D 49484452 .PNG........IHDR
Attempt 2:
$ convert image.png -depth 16 image.rgb
This gives a file size of 1843200 bytes, which is 640*480*2*3.
I'm running imagemagick version 6.7.7-10 on Ubuntu 14.04.
Any ideas?
Updated Answer
It occurred to me since answering you, that there is a simpler method of doing what you want, that takes advantage of ImageMagick's little-used stream tool, to stream raw pixel data around.
In effect, you can use this command
stream -map r -storage-type short image.png image.raw
which will read the Red channel (-map r), which is the same as the Green and Blue channels if your image is greyscale, and write it out as unsigned 16-bit shorts (-storage-type short) to the output file image.raw.
This is cleaner than my original answer - though should give identical results.
Original Answer
If you write an RGB raw file, you will get 3 channels - R, G and B. Try writing a PGM (Portable Greymap) like this...
convert image.png -depth 16 pgm:-
P5
640 480
65535
<binary data> < binary data>
The PGM format is detailed here, but suffice to say that there is header with a P followed by a digit describing the actual subtype, then a width and height and then a MAX VALUE that describes the range of the pixel intensities. In your case, the MAX VALUE is 65535 rather than 255 because your data are 16-bit.
You can the strip the header like this:
convert image.png -depth 16 pgm:- | tail -c 614400 > file.raw
If you are converting lots of files of different sizes and dislike the hard-coded 614400, and are using bash, you can get ImageMagick to tell you the size (height * width * 2 bytes/pixel) and use that like this:
bytes=$(identify -format "%[fx:h*w*2]" image.png)
convert image.png -depth 16 pgm:- | tail -c $bytes > file.raw
gray might be the format you want:
convert image.png -depth 16 image.gray
This command stores each pixel in 2 bytes and nothing else in the file.
Here I provide a minimal synthetic example: https://superuser.com/questions/294270/how-to-view-raw-binary-data-as-an-image-with-given-width-and-height/978432#978432
.raw is not really a "pixel only" format: it does contain some metadata: https://en.wikipedia.org/wiki/Raw_image_format#File_contents
I have image in csv file and i want to load it in my program. I found that I can load image from cvs like this:
CvMLData mlData;
mlData.read_csv(argv[1]);
const CvMat* tmp = mlData.get_values();
cv::Mat img(tmp, true),img1;
img.convertTo(img, CV_8UC3);
cv::namedWindow("img");
cv::imshow("img", img);
I have RGB picture in that file but I got grey picture... Can somebody explain me how to load color image or how can I modify this code to get color image?
Thanks!
Updated
Ok, I don't know how to read your file into OpenCV for the moment, but I can offer you a work-around to get you started. The following will create a header for a PNM format file to match your CSV file and then append your data onto the end and you should end up with a file that you can load.
printf "P3\n284 177\n255\n" > a.pnm # Create PNM header
tr -d ',][' < izlaz.csv >> a.pnm # Append CSV data, after removing commas and []
If I do the above, I can see your bench, tree and river.
If you cannot read that PNM file directly into OpenCV, you can make it into a JPEG with ImageMagick like this:
convert a.pnm a.jpg
I also had a look at the University of Wisconsin ML data archive, that is read with those OpenCV functions that you are using, and the format of their data is different from yours... theirs is like this:
1000025,5,1,1,1,2,1,3,1,1,2
1002945,5,4,4,5,7,10,3,2,1,2
1015425,3,1,1,1,2,2,3,1,1,2
1016277,6,8,8,1,3,4,3,7,1,2
yours looks like this:
[201, 191, 157, 201 ... ]
So maybe this tr command is enough to convert your data:
tr -d '][' < izlaz.csv > TryMe.csv
Original Answer
If you run the following on your CSV file, it translates commas into newlines and then counts the lines:
tr "," "\n" < izlaz.csv | wc -l
And that gives 150,804 lines, which means 150,804 commas in your file and therefore 150,804 integers in your file (+/- 1 or 2). If your greyscale image is 177 rows by 852 columns, you are going to need 150,804 RGB triplets (i.e. 450,000 +/- integers) to represent a colour image, as it is you only have a single greyscale value for each pixel.
The fault is in the way you write the file, not the way you read it.
To see color image I must set number of channels. So this code works for me:
CvMLData mlData;
mlData.read_csv(argv[1]);
const CvMat* tmp = mlData.get_values();
cv::Mat img(tmp, true),img1;
img.convertTo(img, CV_8UC3);
img= img.reshape(3); //set number of channels
I have a large Tiff image that I want to chop into 512x512 tiles and write to disk.
In the past I've used ImageMagick like so:
convert -crop 512x512 +repage image_in.tif image_out_%d.tif
But recently this hasn't been working, processes running out of memory, etc.
Is there a similar command in VIPS? I know there's a CLI but I can't find an example or useful explanation in the documentation, and I'm still trying to figure out the nip2 GUI thing. Any help appreciated. :)
libvips has a operator which can do this for you very quickly. Try:
$ vips dzsave wtc.tif outdir --depth one --tile-size 512 --overlap 0 --suffix .tif
That's the DeepZoom writer making a depth 1 pyramid of tif tiles. Look in outdir_files/0 for the output tiles. There's a chapter in the docs talking about how to use dzsave.
It's a lot quicker than IM for me:
$ time convert -crop 512x512 +repage huge.tif x/image_out_%d.tif
real 0m5.623s
user 0m2.060s
sys 0m2.148s
$ time vips dzsave huge.tif x --depth one --tile-size 512 --overlap 0 --suffix .tif
real 0m1.643s
user 0m1.668s
sys 0m1.000s
Where huge.tif is a 10,000 by 10,000 pixel uncompressed RGB image. Plus it'll process any size image in only a small amount of memory.
I am running into the same issue. It seems that VIPS does not have a built-in command like the one from imagemagick above, but you can do this with some scripting (Python-code snippet):
for x in xrange(0, tiles_per_row):
xoffset = x * tile_size
for y in xrange(0, tiles_per_row):
yoffset = y * tile_size
filename = "%d_%d_%d.png" % (zoom, x, y)
command = "vips im_extract_area %s %s %d %d %d %d" % (base_image_name, filename, xoffset, yoffset, tile_size, tile_size)
os.system(command)
However you won't get the same speed as with imagemagick cropping...