Grayscale image not a jpeg - python

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')

Related

Convert Image to array and array to image using python, does the array contain metadata or other info?

Sorry for my english but it's not my first language.
I would like to create a program that:
Transform a jpeg or png image into an array (very important: I would like an array composed only of the values that the pixels of the image have and not metadata or other information. Where I can select each specific pixel of the image).
Save this array in a txt file.
Transform this array composed of only the pixel values of the image back into jpg or png image and save it in a file.
Requests:
Is the array I created with the program I wrote composed only of the pixel values of the image? is there also metadata or other information?
Is this a valid way to remove metadata from an image?
Is this a valid way to create the array representing that image pixel by pixel?
Is this a valid way to convert png images to jpeg or jpeg to png?
Thank you!
This is the program I created, any opinion?
import numpy as np
from PIL import Image
import sys
img_data = Image.open("imagea.jpeg")
img_arr = np.array(img_data)
np.set_printoptions(threshold=sys.maxsize)
print(img_arr.shape)
new_img = Image.fromarray(img_arr)
new_img.save("imageb.jpeg")
print("Image saved!")
file = open("file1.txt", "w+")
content = str(img_arr)
file.write(content)
file.close()
print("Finished!")
Loading an image and converting it to a Numpy array is a perfectly legitimate way of discarding all metadata including:
EXIF data, copyright data,
IPTC and XMP data,
ICC colour profile data
You can tell it's all gone by thinking about the Numpy array you hold and its dimensions and data type.
Note that you need to be careful with PNG palette images and images with an alpha channel.
Note that you can achieve this more simply on the command-line with ImageMagick using:
magick mogrify -strip IMAGE.JPG
Or with exiftool.
Note that you can achieve this by using a format that doesn't support metadata, such as NetPBM, with extension .ppm e.g.:
magick INPUT.JPG -strip -compress none RESULT.PPM # gives P3/plain ASCII file
magick INPUT.JPG -strip RESULT.PPM # gives P6/binary file
You can also read/write PPM files with PIL.

PIL - resizing an image - different numpy array

I am reading an image from S3 bucket, then resize the image and get the numpy array of the resized image, called "a". I also save the resized image and reopen it and get the numpy array of that called "b". My question is why a and b are different?
resp = s3.get_object(Bucket=event['bucket'], Key=event['image_keys'][0])
data = resp['Body']
image_as_bytes = io.BytesIO(data.read())
image = Image.open(image_as_bytes).convert('RGB').resize((299, 299),Image.NEAREST)
a = np.asarray(image)
image.save('IMAGE_58990004_110132026B_13d64039_resized_lambda.jpg')
b = np.asarray(Image.open('IMAGE_58990004_110132026B_13d64039_resized_lambda.jpg'))
Does ".save" changes the numpy array?
Assuming that image.save(...) uses the filename ending (.jpg) to pick a file format (I don't know if it does. but it seems reasonable), then you are saving as a JPEG file, and the JPEG compression algorithm is lossy, i.e, it discards some information to make the file smaller.
Try using a file format with lossless compression, such as PNG.

How to change the value of each pixel in an image in python?

in order to make a filter for an image softwares change the value of pixels in an image .
when i tried this code
file = open("hey.jpg" , "rb") #opening file
x = file.read() #reading from file
for i in range(len(x)):
print(x[i]) #cordinate of each pixel
file.close() #closing file
i knew it was ouputing the informations of each pixel by the output because no value was above 255 or lower then 0 .
example of ouput from my image:
240 -> R
255 -> G
0 -> B
i want to change the value for each one and save it in a new image
i tried the following code but it doesn't work
file = open("hey.jpg" , "rb") #opening file
x = file.read() #reading from file
file.close() #closing file
file = open("new.jpg" , "wb") #the new image
for i in range(len(x)): #writing the new data with filter
if x[i] !=255: #pixels RGB cant be 256
file.write(bytes(x[i] + 1)) #bytes because when doig write(x[i]+1) it gives mes an error that a bytee object is required not int
else: #if it is 255 then do nothing
file.write(bytes(x[i]))
file.close()#closing the new image
no need to read this:
PS:
windows 10 , python3.8 .
i tried to make everything simplified .
by doesn't work i mean that there was no errors but OS can't decode it and output an image
i don't want to use any third party library like PIL .
this code copy the binary data of an image and make a new one sucessfully .
file = open("hey.jpg" , "rb") #opening file
x = file.read() #reading from file
file.close() #closing file
file = open("new.jpg" , "wb")
file.write(x)
file.close()
JPEG, PNG and most image file formats don't work like that. They have headers at the start with metadata in, like the date you took the picture, your camera model, your GPS coordinates, the image height, its width and copyright information. After that, they normally store the pixels in a heavily optimised, compressed format so you can't alter the pixels without first decompressing the data. You can then edit them and write them back, with new headers and recompressed. So you would be well advised to use a library.
If you really, really don't want to use a Python library, you could use ImageMagick (a command-line tool) in the Terminal to convert your image into pure RGB pixels. So, if your image is called input.jpg, you could run this in Terminal:
magick input.jpg -depth 8 RGB:pixels.dat
And then if your image was 640x480 pixels, your file called pixels.dat will just be exactly 640x480x3 bytes long with no headers or metadata or compression. You could then process this exactly as you initially envisaged. Afterwards, you could make it back into a JPEG or PNG with:
magick -depth 8 -size 640x480 RGB:pixels.dat output.jpg
Notice how you have to tell ImageMagick the height and width of the image for the return journey from RGB bytes to JPEG, because there is no header at the start of the file saying its height and width.
i knew it was ouputing the informations of each pixel by the output because no value was above 255 or lower then 0
Cause of this behavior is different than being "informations of each pixel" - you did simply accessed individual bytes of your file and 1 byte value is always from 0x00 (inclusive) to 0xFF (inclusive). Result will be similar if you do this on file of other type (for example text one).
this code copy the binary data of an image and make a new one sucessfully .
Your code simply copied content of file into another file. Note that it will work regardless of file type.
i don't want to use any third party library like PIL
Do as you wish, but keep in mind that without "any third party library" you must implement processing of every image format yourself from scratch.

How to convert .tif image to .jpg using skimage

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 ")

Encode part image in python

Now I want to encode part image in base64 and I did do it. For example, here is an image 1080x1920, but part of this image is needed.
Top:160, left:340, right:1024, bottom:650.
# first crop
im = Image.open(original)
region = im.crop((160, 340, 1024, 650))
clip_image = os.path.join(screenshot_dir, 'clip.png')
region.save(clip_image)
// then read
f = open(clip_image, 'rb')
ls_f = base64.b64encode(f.read())
f.close()
s = bytes.decode(ls_f)
In my opinion, maybe I do not have to save resized image and I can read part of this image directly. If so, the program can run faster because there is no extra IO operation.
You can use tobytes for a raw image
This method returns the raw image data from the internal storage. For
compressed image data (e.g. PNG, JPEG) use save(), with a BytesIO
parameter for in-memory data.
im = Image.open(original)
region = im.crop((160, 340, 1024, 650))
ls_f = base64.b64encode(region.tobytes())
s = bytes.decode(ls_f)
If it is a png or jpg, you need to use BytesIO, perhaps like this:
im = Image.open(original)
region = im.crop((160, 340, 1024, 650))
with io.BytesIO() as temp_file:
region.save(temp_file)
ls_f = base64.b64encode(temp_file.getvalue())
s = bytes.decode(ls_f)
it depends on the format of the input image. If it is not compressed, like a bitmap bmp, it's raw. Examples of compressed formats are png, jpeg, gif. Easiest way is to look at the extension, or to try it out. If you try the first approach on a compressed image, it'll probably raise an Exception, or return a distorted image

Categories

Resources