I am trying to convert from base64 to PIL image and PIL image to base64. And I am using these scripts.
def convert_base64_2_pil_image(image_b64: bytes) -> Image:
image_str = base64.b64decode(image_b64)
return Image.open(io.BytesIO(image_str))
def convert_pil_image_2_base64(image: Image, format: str = 'PNG') -> bytes:
buffered = io.BytesIO()
image.save(buffered, format=format)
buffered.seek(0)
return base64.b64encode(buffered.getvalue())
When I try to convert one base64 string to a PIL image and again convert that PIL image to base64 the base64 strings are not the same. I am losing some information.
image_b64 = b'iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mP8/5+hHgAHggJ/PchI7wAAAABJRU5ErkJggg=='
image = convert_base64_2_pil_image(image_b64)
image_b64_converted = convert_pil_image_2_base64(image)
assert image_b64_converted == image_b64
How can I fix this problem?
The fact that your base-64 strings differ does not necessarily mean that you have lost information. If you want a better analysis/answer you will need to provide your images and base-64 representations in their exact, original form - probably via Dropbox or Google Drive - because most websites strip images of geographic and other information which affects the base-64 representation.
So, going back to your question, there are several possible explanations of why the base-64 representation could differ:
firstly, a PNG image often includes a date/time of last change as the ancillary tIME chunk, so merely opening and resaving a solid black image 1 second later could change the base-64 representation
secondly, although lossless, it is not guaranteed that two libraries will make the same decisions in terms of bit-depth, palette, alpha, filtering and so on. For example, one library may choose to save an image with a limited number of colours as a palette image, whereas another may choose an RGB representation and another may choose an RGBA representation. See here. One may choose an 8-bit per sample PNG, another may choose a 16-bit per sample PNG.
Related
I have code that takes an image and converts it into a bitmap. I was wondering if there was a way to save the bitmap in a separate file to be used later. I would like to also be able to open that file in plain text and not an actual image so that I can read the bitmap.
code:
image_file = Image.open("edge.png")
image_file = image_file.convert('1')
print(image_file.mode)
print(type(image_file.tobitmap()))
tobit_image = image_file.tobitmap() # convert image to bitmap
print(tobit_image)
I think you are looking for "Chain Codes", or "Freeman Chain Codes". Basically, you store a direction, which is one of the 8 points of the compass encoded as a digit at each location to tell you how to get get to the next point, i.e. which direction your turtle must move.
Try looking here and also Googling.
OpenCV can generate them too with findContours()
Or, you may be looking for potrace which is a tool that converts images into vector paths.
I have a file with a lot of .tif images.
Part 1. Preview of TIFF images
When I try to opreview them by clicking on them in the jupyter folder (which look like this one the Jupyter folder), I get the following message :
Error ! D:...\image.tif is not UTF-8 encoded
On the opposite, if I click on a png in the Jupyter folder, Jupyter does display an image.
How could I fix my images, knowing that I have more than 1000 of them in my folder ?
Nonetheless, if I write :
sph = cv2.imread('A1.tif',-1)
plt.imshow(sph)
plt.show()
I do get the image : image of 'A1.tif'.
Now I also checked :
import chardet
chardet.detect('A1.det')
--> {'confidence': 1.0, 'encoding': 'ascii', 'language': ''} # result
So apparently I it is encoded in ascii. Is it the same as utf-8 or should I convert them ?
Edit : Answer : In one of the comments, #FabienP answers that "According the official documentation, Jupyter lab does not support TIFF format for image preview (as of now)", which answers this question.
Part 2 : writing a video out of TIFF images
I have another question and I don't know if both questions are connected.
I want to make a video out of them.
import cv2
import os
image_folder = 'A549_A1'
video_name = 'video.avi'
images = [img for img in os.listdir(image_folder) if img.endswith(".tif")]
frame = cv2.imread(os.path.join(image_folder, images[0]))
height, width, layers = frame.shape
video = cv2.VideoWriter(video_name, 0, 1, (width,height))
for image in images:
video.write(cv2.imread(os.path.join(image_folder, image)))
cv2.destroyAllWindows()
video.release()
But instead of getting the expected video, I get a strange one with many images at one step : caption of the video. You can compare it to the image above to check that it's not normal.
How can I fix that ?
Converting the bytes in an image from ASCII to UTF-8 makes only slightly more sense than converting them from Fahrenheit to Celsius, or transposing them to B♭ major. If you can find a way to do it technically, all it will do is wreck the image. Indeed, this is completely a red herring, and has absolutely nothing to do with your video conversion problem.
Text encodings like ASCII and UTF-8 describe how characters map between code points or glyphs and computer representations. There is no text in an image file; it is just a bunch of pixels. Maybe see also the seminal 2003 blog post The Absolute Minimum Every Software Developer Absolutely, Positively Must Know About Unicode and Character Sets (No Excuses!)
Moreover, because UTF-8 is ASCII compatible, every ASCII file is already trivially a UTF-8 file. There is no transformation you can apply to make it "more UTF-8".
Binary formats, on the other hand, typically have an internal structure which is quite different. For just an image, a trivial format might simply encode each black pixel as a 1 bit and each white pixel as a 0 bit. (In fact, the very first version of TIFF did exactly this, with a few additional frills.) You can add a constant to each byte, for example, but this will simply transform it into a jumble which no longer contains a valid picture. Examine what happens if you add one to a number like 63 which has a lot of 1 bits in the lower half in its binary representation:
63 0011 1111 ..XX XXXX <- sequence of black pixels
+ 1 + 0000 0001 .... ...X
---- ----------- ----------
64 0100 0000 .X.. .... <- one black pixel, lots of white
Modern binary formats are quite a bit more complex, and often contain header sequences which indicate how many bytes of data follow or where to look for a particular feature to populate a data structure in memory. Replacing these values with other values will almost certainly create a stream which is simply corrupted unless you know exactly what you are doing.
Comparing against https://stackoverflow.com/a/34555939/874188 and googling for a bit suggests that passing 0 as the fourcc parameter might be the source of your problems.
I want to save floating-point numbers as pixels in an image file. I am currently working in OpenCV-python, but I had also tried it with Pillow (PIL). Both packages convert float pixel data to integer before writing them to the file.
I want to save pixel values such as:
(245.7865, 123.18788, 98.9866)
But when I read back the image file I get:
(246, 123, 99)
Somehow my floating-point numbers get rounded off and converted to integers.
How to stop PIL or OpenCV from converting them to integer?
Raster images are normally stored as integer values only. Instead save the numpy array directly like so
x = numpy.array([1, 2, 3])
with open('x.npy', 'wb') as f:
numpy.save(f, x)
Then load the variable back like so
x = numpy.load('x.npy')
Other alternatives include
Save one or more GRAY16 png images, with your floats multiplied and truncated.
Use the Netpbm format supporting floats.
Save a pickle.
The behavior you observe depends on the file format in which you save the image. Few image formats have a specification for floating-point pixel values. Though some do, first and foremost TIFF.
To demonstrate the desired behavior with a TIFF image writer, consider the following script. It uses the versatile image input/output library ImageIO, which relies on PILlow as one of its back-ends:
# Use Stack Overflow logo as sample image.
import imageio
logo = 'https://cdn.sstatic.net/Sites/stackoverflow/img/logo.png'
image = imageio.imread(logo)
# Normalize to 1. Pixel values are now floating-point.
image = image / image.max()
# Save as image file and read back in.
format = 'tiff'
imageio.imwrite(f'image.{format}', image)
print(f'wrote: {image.dtype}')
image = imageio.imread(f'image.{format}')
print(f'read: {image.dtype}')
The output of that script is:
wrote: float64
read: float64
If, on the other hand, you change the format to PNG (format = 'png' in the code), the output is:
Lossy conversion from float64 to uint8. Range [0, 1].
Convert image to uint8 prior to saving to suppress this warning.
wrote: float64
read: uint8
This is a code of a JPG/PNG(I don't know exactly)
Here's on google docs
I need to decode it in Python to complete image and show it using Pillow or something like that. Do you know any libraries or ways how to decode it? Thanks!
(for Python 3)
If the image is stored as a binary file, open it directly:
import PIL
# Create Image object
picture = PIL.Image.open('picture_code.dat')
#display image
picture.show()
# print whether JPEG, PNG, etc.
print(picture.format)
If the image is stored as hex in a plaintext file picture_code.dat similar to your Google Docs link, it needs to first be converted to binary data:
import binascii
import PIL
import io
# Open plaintext file with hex
picture_hex = open('picture_code.dat').read()
# Convert hex to binary data
picture_bytes = binascii.unhexlify(picture_hex)
# Convert bytes to stream (file-like object in memory)
picture_stream = io.BytesIO(picture_bytes)
# Create Image object
picture = PIL.Image.open(picture_stream)
#display image
picture.show()
# print whether JPEG, PNG, etc.
print(picture.format)
I have some images I want to analyze using a python script.
They are stored as raw binary data files. They are in the following format. 16-bit unsigned, big endian, 592x600 pixels with a 520 byte header.
When I look at the .dat file in my OS (OS X yosemite) I see that the file is 710,920 bytes
This makes sense as (592 x 600 pixels) * (2 bytes per pixel) = 710,400 bytes. Thus the remainder is the 520 byte header.
I want to write a quick python script to generate an array of the pixel values. i.e. I want to ditch the header of the file and store the rest of the data as an array so that I can use something like PIL to then quickly convert into an image and output a jpg or png.
Just doing something really quick quick:
myfile = open('test.dat', 'rb')
data = myfile.read()
len(data)
trimdata = data[520:]
len(trimdata)
This gives me the raw data without the header.
From here I am unsure about the easiest way to parse the data into a 592x600 array that I can then use with PIL to export a quick greayscale image.
here is a link to the file incase that helps out:
test.dat
Edit: Thanks for all the help - It appears the data was Little Endian not Big Endian after all. Cheers.
You can convert them to quick JPEGs without writing any Python at all using ImageMagick's convert from the commandline.
Just tell ImageMagick the size and bit depth and data offset and it can make a greyscale JPEG or 16-bit TIFF for you.
Something like this but I do not have my Mac to hand to test:
convert -size 592x600+520 -depth 16 GRAY:image.dat output.jpg
You may need -endian MSB (or LSB) before the first filename too.
I am back at my Mac now, and the command to produce this image is:
convert -size 592x600+520 -depth 16 -endian MSB GRAY:image.dat -auto-level output.jpg
PIL should be able to read that data directly, but heck if I can figure out how to do it. It doesn't take too many steps to do it indirectly though.
fmt = '>' + str(592*600) + 'H'
pix = struct.unpack(fmt, trimdata)
scaled_pix = ''.join(chr(p/256) for p in pix)
im = Image.fromstring('L', (592,600), scaled_pix, 'raw')
Edit: It looks like your sample picture is little-endian, not big-endian. Here's some corrected code. I also threw in automatic brightness scaling and gamma correction, since the full 16-bit scale wasn't being used.
fmt = '<' + str(592*600) + 'H'
pix = struct.unpack(fmt, trimdata)
lightest = max(pix)
scaled = ''.join(chr(int((float(p) / lightest)**(1/2.2) * 255)) for p in pix)
im = Image.fromstring('L', (592,600), scaled, 'raw')