I'm trying to convert some matlab code to python and the im2double function is giving me trouble. It takes an image and returns a matrix with the pixels using doubles instead of ints.
Currently I'm manipulating my images with PIL. It has a convert method that can take 'F' as parameter, but all it does is convert the integer value 255 to 255.0. Useless as far as I can tell.
The problem I have is that I'm doing some image manipulation and then have to save them. I can normalize my values so that they fall into the 0-255 range, but I lose some precision. It's small enough that it shouldn't normally matter, but here, it does.
I've tried using the 'tiff' file format and that didn't work out well. Though I can write/read to it, the results I get are not the right ones, which I can only get at the moment converting the pixels to 255 which results in a loss of precision, as I said previously. I also tried this 'SPIDER' file format thing I found on google previously that PIL supports though I couldn't open the image on an editor to check how it was doing.
The way to do this properly in Python will to use Numpy. You can read images via PIL into numpy arrays. At this point a wide range of Matlab like matrix operations become available to you via numpy/scipy. Changing the precision of the array is simply a matter of switching the arrays datatype via numpy. Recent releases of PIL include the patch from Travis Oliphant to allow you to do this without extra hackery.
Saving the data to a more commonly readable image format can be achieved by using a floating point TIFF without loss of precision. I use the GDAL library to interface to multiple image format writers/readers. If you want lossless compression TIFF can compress using zlib as well.
Related
I am working on a dataset that has two features, real and imaginary impedances. I applied data-to-image conversion using MTF in order to represent each one as an image (50x50). I was thinking of creating a 3-D image (50x50x2). I tried doing
Image = np.array([tag_gadf_re[0],tag_gadf_im[0]])
where tag_gadf_re[0] and tag_gadf_im[0] are the real and imaginary impedance image arrays. However, I tried saving the image using:
plt.imsave("Directory", Image)
However, I am getting the following error:
ValueError: Third dimension must be 3 or 4
Also note that the shape of Image is (2x50x50), when it should be (50x50x2). The solution seems simple, but I am a bit lost in the process. How can I combine both arrays appropriately and save the image, or do I need a 3rd layer in order to appropriately represent it as an RGB image?
If you want to store data as an image you need to be aware of its type and range so that you can choose an appropriate format. You also need to be aware of whether you can tolerate a "lossy" format which, when read, will not return identical values to those you stored.
If your data is integer and 16-bit or less, you can store it in a PNG. If it's multi-channel and 16-bit, you'll come unstuck with PIL. You can use tifffile though to store a 2-channel TIFF - maybe that can be greyscale + transparency or maybe 2 IFDs.
If your data is floating point, you pretty much have to use TIFF, PFM or EXR format. Again, tifffile can do this for you.
tifffile is here.
wand can also do whatever tifffile can do.
Of course, you might choose to represent your two arrays/images as one above the other in a double-height image. It's your data.
I am working on bayer raw(.raw format) image domain where I need to edit the pixels according to my needs(applying affine matrix) and save them back .raw format.so There are two sub-problems.
I am able to edit pixels but can save them back as .raw
I am using a robust library called rawpy that allows me to read pixel values as numpy array, while I try to save them back I am unable to persist the value
rawImage = rawpy.imread('Filename.raw') // this gives a rawpy object
rawData = rawImage.raw_image //this gives pixels as numpy array
.
.//some manipulations performed on rawData, still a numpy array
.
imageio.imsave('newRaw.raw', rawData)
This doesn't work, throws error unknown file type. Is there a way to save such files in .raw format.
Note: I have tried this as well:-
rawImageManipulated = rawImage
rawImageManipulated.raw_image[:] = rawData[:] //this copies the new
data onto the rawpy object but does not save or persists the values
assigned.
Rotating a bayer image - I know rawpy does not handle this, nor does any other API or Library acc to my knowledge. The existing image rotation Apis of opencv and pillow alter the sub-pixels while rotating. How do I come to know? After a series of small rotations(say,30 degrees of rotation 12 times) when I get back to a 360 degree of rotation the sub-pixels are not the same when compared using a hex editor.
Are there any solutions to these issues? Am I going in the wrong direction? Could you please guide me on this. I am currently using python i am open to solutions in any language or stack. Thanks
As far as I know, no library is able to rotate an image directly in the Bayer pattern format (if that's what you mean), for good reasons. Instead you need to convert to RGB, and back later. (If you try to process the Bayer pattern image as if it was just a grayscale bitmap, the result of rotation will be a disaster.)
Due to numerical issues, accumulating rotations spoils the image and you will never get the original after a full turn. To minimize the loss, perform all rotations from the original, with increasing angles.
I am a bit confused about when an image is gamma encoded/decoded and when I need to raise it to a gamma function.
Given an image 'boat.jpg' where the colour representation is labeled 'sRGB'. My assumption is that the pixel values are encoded in the file by raising the arrays to ^(1/2.2) during the save process.
When I import the image into numpy using scikit-image or opencv I end up with a 3-dim array of uint8 values. Do these values need to be raised to ^2.2 in order to generate a histogram of the values, or when I apply the imread function, does that map the image into linear space in the array?
from skimage import data,io
boat = io.imread('boat.jpg')
if you get your image anywhere on the internet, it has gamma 2.2.
unless the image has an image profile encoded, then you get the gamma from that profile.
imread() reads the pixel values 'as-is', no conversion.
there's no point converting image to gamma 1.0 for any kind of the processing, unless you specifically know that you have to. basically, nobody does that.
As you probably know, skimage uses a handful of different plugins when reading in images (seen here). The values you get should not have to be adjusted...that happens under the hood. I would also recommend you don't use the jpeg file format because you lose data with the compression.
OpenCV (as of v 4) usually does the gamma conversion for you, depending on the image format. It appears to do it automatically with PNG, but it's pretty easy to test. Just generate a 256x256 8-bit color image with a linear color ramps along x and y, then check to see what the pixel values at given image coords. If the sRGB mapping/unmapping is done correctly at every point, x=i should have pixel value i and so on. If you imwrite to PNG in OpenCV, it will convert to sRGB, tag that in the image format, and GIMP or whatever will happily decode it back back to linear.
Most image files are stored as sRGB, and there's a tendency for most image manipulation APIs to handle it correctly, since well, if they didn't, they'd work wrong most of the time. In the odd instance where you read an sRGB file as linear or vice versa, it will make a significant difference though, especially if you're doing any kind of image processing. Mixing up sRGB and linear causes very significant problems, and you will absolutely notice it if it gets messed up; fortunately, the software world usually handles it automagically in the file read/write stage so casual app developers don't usually have to worry about it.
I'm trying to write a steganography applcation using the LSB method and it works so far well enough for a few image formats .
However it doesn't work for GIF images since i have noticed that the saved gif has a few different pixel values (usually +- 1) and the LSB method relies on changing the least significant bit so a few different values throws the decoding algorithm off.
i have tried using both imageio and PIL.Image and it's the same problem in both cases
So basically my question is : Why does the pixel values change when saved and is it even possible to use LSB for encoding and decoding a GIF ?
Thanks for your help.
Gif is lossless it should not change the pixels, I recently did a little application using LSB method with gif format here is few things you should do:
make sure when you encoded right, try replacing the pixel(0,0) then verify if the value is change if not so check the decoding
make sure that the gif color is 255
you will encounter this later but you should put the original metadata and delay time when assembling the frames
These are the main issues, other than that as I said earlier it is a lossless compression just like png it should not change the pixels so the problem is either in coding/decoding or type of the RGB color.
I wrote the following code:
from moviepy.editor import *
from PIL import Image
clip= VideoFileClip("video.mp4")
video= CompositeVideoClip([clip])
video.write_videofile("video_new.mp4",fps=clip.fps)
then to check whether the frames have changed or not and if changed, which function changed them, i retrieved the first frame of 'clip', 'video' and 'video_new.mp4' and compared them:
clip1= VideoFileClip("video_new.mp4")
img1= clip.get_frame(0)
img2= video.get_frame(0)
img3= clip1.get_frame(0)
a=img1[0,0,0]
b=img2[0,0,0]
c=img3[0,0,0]
I found that a=24, b=24, but c=26....infact on running a array compare loop i found that 'img1' and 'img2' were identical but 'img3' was different.
I suspect that the function video.write_videofile is responsible for the change in array. But i dont know why...Can anybody explain this to me and also suggest a way to write clips without changing their frames?
PS: i read the docs of 'VideoFileClip', 'FFMPEG_VideoWriter', 'FFMPEG_VideoReader' but could not find anything useful...I need to read the exact frame as it was before writing in a code I'm working on. Please, suggest me a way.
Like JPEG, MPEG-4 uses lossy compression, so it's not surprising that the frames read from "video_new.mp4" are not perfectly identical to those in "video.mp4". And as well as the variations caused purely by the lossy compression there are also variations that arise due to the wide variety of encoding options that can be used by programs that write MPEG data.
If you really need to be able to read back the exact same frame data that you write then you will have to use a different file format, but be warned: your files will be huge!
The choice of video format partly depends on what the image data is like and on what you want to do with it. If the data uses 256 colours or less, and you don't intend to perform transformations on it that will modify the colours, a simple GIF anim is a good choice. But bear in mind that even something like non-integer scaling modifies colours.
If you want to analyze the image data and transform it in various ways, it makes sense to use a format with better colour support than GIF, eg a stream of PNG images, which I assume is what Zulko mentions in his answer. FWIW, there's an anim format related to PNG called MNG, but it is not well supported or widely known.
Another option is to use a stream of PPM images, or maybe even a stream of YUV data, which is useful for certain kinds of analysis and convenient if you do intend to encode as MPEG for final consumption. The PPM format is very simple and easy to work with; YUV is slightly messy since it's a raw format with no header data, so you have to keep track of the image size and resolution data yourself.
The file size of PPM or YUV streams is large, since they incorporate no compression at all, but of course they can be compressed using standard compression techniques, if you want to save a little space when saving them to disk. OTOH, typical video processing workflows that use such streams often don't bother writing them to disk: they are sent in pipelines (perhaps using named pipes), so the file size is (mostly) irrelevant.
Although such formats take up a lot of space compared to MPEG-based files, they are far superior for use as intermediate formats while performing image data analysis and transformation, since every time you write & read back MPEG you are losing a little bit of quality.
I assume that you intend to do your image data analysis and transformations using PIL/Pillow. But you can also work with PPM & YUV streams using the ffmpeg / avconv command line programs; and the ffmpeg family happily work with sets of individual image files and GIF anims, too.
You can have lossless compression with the 'png' codec:
clip.write_videoclip('clip_new.avi', codec='png')
EDIT #PM 2Ring: when you write the line above, it makes a video that is compressed using the png algortihm (I'm not sure whether each frame is a png or if it's more subtle).