I'm trying to convert a .tif image in python using the module skimage.
It's not working properly.
from skimage import io
img = io.imread('/content/IMG_0007_4.tif')
io.imsave('/content/img.jpg', img)
Here is the error:
/usr/local/lib/python3.6/dist-packages/imageio/core/functions.py in get_writer(uri, format, mode, **kwargs)
if format is None:
raise ValueError(
"Could not find a format to write the specified file " "in mode %r" % mode)
ValueError: Could not find a format to write the specified file in mode 'i'
EDIT 1:
A method I found to do this was to open using skimage, convert it to 8bits and then save it as png.
Anyway I can't save it as .jpg
img = io.imread('/content/IMG_0007_4.tif',as_gray=True)
img8 = (img/256).astype('uint8')
matplotlib.image.imsave('/content/name.png', img8)
You have not provided an image plugin in the save command. See https://scikit-image.org/docs/dev/api/skimage.io.html#skimage.io.imsave where it says:
When saving a JPEG, the compression ratio may be controlled using the
quality keyword argument which is an integer with values in [1, 100]
where 1 is worst quality and smallest file size, and 100 is best
quality and largest file size (default 75). This is only available
when using the PIL and imageio plugins.
I found a good tool called ImageMagick it can be installed in linux.
To call it inside python code i just did this.
os.system("convert image.png -colorspace RGB image.jpg ")
Related
I am trying to read this file using Pillow and cv2 in python. However, both libraries are failing to do so.
File is here on google drive.
Pillow raises an "OSError: cannot identify image file 0.jpg"
cv2 returns None
This binary file has the extension ".jpg" and can be easily viewed using Window`s Photos viewer.
However, I want to read and decode this binary file as an image in python.
Any idea?
Your file is actually a JXR file, you can see the first few bytes are:
49 49 BC
if you load it into a hex editor like http://hexed.it
The signature is IANA registered, see here.
You can read it with imagecodecs like this:
import imagecodecs
from pathlib import Path
# Slurp entire image data as binary
jxr = Path('0.jpg').read_bytes()
# Make into Numpy array
na = imagecodecs.jpegxr_decode(jxr)
print(na.shape) # prints (256, 512, 3)
Alternatively, you can convert JXR to something less Microsofty with ImageMagick in your Terminal with:
magick input.jxr output.jpg
Or, if you have old v6 ImageMagick, use:
convert input.jxr output.jpg
I created a greyscale image like this
def create_new_image(size, luminance):
width, height = size
black_frame = int(luminance) * np.ones((width, height, 1), dtype=np.uint8)
return black_frame
Where luminance is element of [0, 255]
I have saved the image using imageio
def save_image(image, output_path):
imageio.imwrite(output_path, image)
Where the output_path is something like /valid_path/img.jpg
Now I want to load my grayscale image back:
img = imageio.imread(file, format ='jpg')
But what I get is a syntax error.
raise SyntaxError("not a JPEG file")
File "<string>", line None
SyntaxError: not a JPEG file
If I don't specify the format, I get another error.
"Could not find a format to read the specified file in %s mode" % modename
ValueError: Could not find a format to read the specified file in single-image mode
Why?
Thanks
You can try :
def save_image(image, output_path):
imageio.imwrite(output_path, format= "jpg", image)
to explicitly state that it is a jpg file.
JPEG files (compressed images) start with an image marker that always contains the marker code hex values FF D8 FF. It does not have a length of the file embedded, thus we need to find JPEG trailer, which is FF D9.
See the documentation using the link at this page.
As en example, opening a jpeg image with a hexadecimal viewer (for example Hex Viewer), you should see something like this:
Solution: In other words, try to add the header to the file before saving it as JPEG, you should solve your problem.
The page with the API's documentation can be found here. Following the doc, you should locate the right instruction that makes you specify the format for saving (as point out by #Meto in the answer).
Concluding: the solution is just specifying the format when you physically write the image in the hard disk:
imageio.imwrite(uri, im, format=None, **kwargs)
in your case format=jpg.
Moreover,
imageio.show_formats()
Show a nicely formatted list of available formats.
Concluding, just try to replace
imageio.imwrite(output_path, image)
with
imageio.imwrite(output_path, image, format ='jpg' )
Please note that the solution is always the same in every answer. I have just added what happens specifying a format (i.e., just writes the right header).
You need to make sure if your file is really saved as a JPG file.
On Linux/Mac you can use file command to verify that.
For example, below command confirms fireside.jpg is a JPEG file:
# file fireside.jpg
fireside.jpg: JPEG image data, JFIF standard 1.01, aspect ratio, density 1x1, segment length 16, baseline, precision 8, 2048x1365, components 3
If the file is not saved as JPG, try specifying file format="jpg" as
imageio.imwrite(output_path, image, format ='jpg')
This works (Verified in jupyter notebook)
import numpy as np
import imageio
def create_new_image(size, luminance):
width, height = size
black_frame = int(luminance) * np.ones((width, height, 1), dtype=np.uint8)
return black_frame
def save_image(image, output_path):
imageio.imwrite(output_path, image)
img = create_new_image((256, 256), 125)
save_image(img, "test.jpg")
img1 = imageio.imread("test.jpg", format ='jpg')
I am taking a screen-shot (PNG format) resizing it, and writing it back out in TIF format, via scipy.misc module (imread, imresize, imsave functions). The TIF format image is to be fed into Tesseract-OCR. However, Tesseract is complaining that the dpi specified in the TIF file's metadata is 0. How can one specify this when saving the image via scipy.misc.imsave or any other method?
Without analyzing where your problems exactly come from, the approach of Mark (maybe that's enough for you; maybe not; i can imagine there is something else in your code which might be the reason) can be emulated by using Pillow (and i don't see an option for this within scipy's wrapper).
Actually, instead of rewriting tags as he does, we care about these while doing our original task. In practice both approaches should be okay.
With a very high probability, scipy is already using Pillow under the hood (Note that Pillow (https://python-pillow.org/) is not a dependency of SciPy, but the image manipulation functions indicated in the list below are not available without it.; this list contains imsave).
from scipy.misc import ascent # test image
import PIL.Image
scipy_img = ascent().astype('uint8')
arr2im = PIL.Image.fromarray(scipy_img)
arr2im.save('test.tif', format='TIFF',
dpi=(100., 100.), # there still seems to be a bug when using int's here
compression='tiff_lzw',)
Checking with exiftool:
ExifTool Version Number : 10.63
File Name : test.tif
...
Image Width : 512
Image Height : 512
Bits Per Sample : 8
Compression : LZW
...
X Resolution : 100
Y Resolution : 100
...
Resolution Unit : inches
Image Size : 512x512
Megapixels : 0.262
Please file this one under "any other method" :-)
You can set the resolution with exiftool like this:
exiftool SomeImage.tif -xresolution=300 -yresolution=300 -resolutionunit=inches
Check it with ImageMagick:
identify -verbose SomeImage.tif
Image: SomeImage.tif
Format: TIFF (Tagged Image File Format)
Mime type: image/tiff
Class: DirectClass
Geometry: 100x100+0+0
Resolution: 300x300
Print size: 0.333333x0.333333
...
...
I am suggesting you shell out to run this command with os.system().
A Python wrapper exists, but I have never used it and cannot vouch for it.
I try to apply image filters using python's PIL. The code is straight forward:
im = Image.open(fnImage)
im = im.filter(ImageFilter.BLUR)
This code works as expected on PNGs, JPGs and on 8-bit TIFs. However, when I try to apply this code on 16-bit TIFs, I get the following error
ValueError: image has wrong mode
Note that PIL was able to load, resize and save 16-bit TIFs without complains, so I assume that this problem is filter-related. However, ImageFilter documentation says nothing about 16-bit support
Is there any way to solve it?
Your TIFF image's mode is most likely a "I;16".
In the current version of ImageFilter, kernels can only be applied to
"L" and "RGB" images (see source of ImageFilter.py)
Try converting first to another mode:
im.convert('L')
If it fails, try:
im.mode = 'I'
im = im.point(lambda i:i*(1./256)).convert('L').filter(ImageFilter.BLUR)
Remark: Possible duplicate from Python and 16 Bit Tiff
To move ahead, try using ImageMagick, look for PythonMagick hooks to the program. On the command prompt, you can use convert.exe image-16.tiff -blur 2x2 output.tiff. Didn't manage to install PythonMagick in my windows OS as the source needs compiling.
I am currently using PIL.
from PIL import Image
try:
im=Image.open(filename)
# do stuff
except IOError:
# filename not an image file
However, while this sufficiently covers most cases, some image files like, xcf, svg and psd are not being detected. Psd files throws an OverflowError exception.
Is there someway I could include them as well?
I have just found the builtin imghdr module. From python documentation:
The imghdr module determines the type
of image contained in a file or byte
stream.
This is how it works:
>>> import imghdr
>>> imghdr.what('/tmp/bass')
'gif'
Using a module is much better than reimplementing similar functionality
UPDATE: imghdr is deprecated as of python 3.11
In addition to what Brian is suggesting you could use PIL's verify method to check if the file is broken.
im.verify()
Attempts to determine if the file is
broken, without actually decoding the
image data. If this method finds any
problems, it raises suitable
exceptions. This method only works on
a newly opened image; if the image has
already been loaded, the result is
undefined. Also, if you need to load
the image after using this method, you
must reopen the image file. Attributes
Additionally to the PIL image check you can also add file name extension check like this:
filename.lower().endswith(('.png', '.jpg', '.jpeg', '.tiff', '.bmp', '.gif'))
Note that this only checks if the file name has a valid image extension, it does not actually open the image to see if it's a valid image, that's why you need to use additionally PIL or one of the libraries suggested in the other answers.
A lot of times the first couple chars will be a magic number for various file formats. You could check for this in addition to your exception checking above.
One option is to use the filetype package.
Installation
python -m pip install filetype
Advantages
Fast: Does its work by loading only the first few bytes of your image (check on the magic number)
Supports different mime type: Images, Videos, Fonts, Audio, Archives.
Example
filetype >= 1.0.7
import filetype
filename = "/path/to/file.jpg"
if filetype.is_image(filename):
print(f"{filename} is a valid image...")
elif filetype.is_video(filename):
print(f"{filename} is a valid video...")
filetype <= 1.0.6
import filetype
filename = "/path/to/file.jpg"
if filetype.image(filename):
print(f"{filename} is a valid image...")
elif filetype.video(filename):
print(f"{filename} is a valid video...")
Additional information on the official repo: https://github.com/h2non/filetype.py
Update
I also implemented the following solution in my Python script here on GitHub.
I also verified that damaged files (jpg) frequently are not 'broken' images i.e, a damaged picture file sometimes remains a legit picture file, the original image is lost or altered but you are still able to load it with no errors. But, file truncation cause always errors.
End Update
You can use Python Pillow(PIL) module, with most image formats, to check if a file is a valid and intact image file.
In the case you aim at detecting also broken images, #Nadia Alramli correctly suggests the im.verify() method, but this does not detect all the possible image defects, e.g., im.verify does not detect truncated images (that most viewers often load with a greyed area).
Pillow is able to detect these type of defects too, but you have to apply image manipulation or image decode/recode in or to trigger the check. Finally I suggest to use this code:
from PIL import Image
try:
im = Image.load(filename)
im.verify() #I perform also verify, don't know if he sees other types o defects
im.close() #reload is necessary in my case
im = Image.load(filename)
im.transpose(Image.FLIP_LEFT_RIGHT)
im.close()
except:
#manage excetions here
In case of image defects this code will raise an exception.
Please consider that im.verify is about 100 times faster than performing the image manipulation (and I think that flip is one of the cheaper transformations).
With this code you are going to verify a set of images at about 10 MBytes/sec with standard Pillow or 40 MBytes/sec with Pillow-SIMD module (modern 2.5Ghz x86_64 CPU).
For the other formats xcf,.. you can use Imagemagick wrapper Wand, the code is as follows:
Check the Wand documentation: here, to installation: here
im = wand.image.Image(filename=filename)
temp = im.flip;
im.close()
But, from my experiments Wand does not detect truncated images, I think it loads lacking parts as greyed area without prompting.
I red that Imagemagick has an external command identify that could make the job, but I have not found a way to invoke that function programmatically and I have not tested this route.
I suggest to always perform a preliminary check, check the filesize to not be zero (or very small), is a very cheap idea:
import os
statfile = os.stat(filename)
filesize = statfile.st_size
if filesize == 0:
#manage here the 'faulty image' case
On Linux, you could use python-magic which uses libmagic to identify file formats.
AFAIK, libmagic looks into the file and tries to tell you more about it than just the format, like bitmap dimensions, format version etc.. So you might see this as a superficial test for "validity".
For other definitions of "valid" you might have to write your own tests.
You could use the Python bindings to libmagic, python-magic and then check the mime types. This won't tell you if the files are corrupted or intact but it should be able to determine what type of image it is.
Adapting from Fabiano and Tiago's answer.
from PIL import Image
def check_img(filename):
try:
im = Image.open(filename)
im.verify()
im.close()
im = Image.open(filename)
im.transpose(Image.FLIP_LEFT_RIGHT)
im.close()
return True
except:
print(filename,'corrupted')
return False
if not check_img('/dir/image'):
print('do something')
Extension of the image can be used to check image file as follows.
import os
for f in os.listdir(folderPath):
if (".jpg" in f) or (".bmp" in f):
filePath = os.path.join(folderPath, f)
format = [".jpg",".png",".jpeg"]
for (path,dirs,files) in os.walk(path):
for file in files:
if file.endswith(tuple(format)):
print(path)
print ("Valid",file)
else:
print(path)
print("InValid",file)