Encode - decode base64 image - python-3.x

I have an image that is obtained from an OpenCV video capture object as such:
import cv2
import base64
from PIL import Image
import io
cap = cv2.VideoCapture(0)
# capture frame by frame
ret, frame = cap.read()
How can I encode and decode the image (i.e. go from raw pixels to bytes and back to raw pixels)?
So far I have been trying the following:
encoded_string = base64.b64encode(frame)
decoded_string = base64.b64decode(encoded_string)
img = Image.open(io.BytesIO(decoded_string))
img.show()
This is giving me an error:
File "/usr/lib/python3/dist-packages/PIL/Image.py", line 2295, in open
% (filename if filename else fp))
OSError: cannot identify image file <_io.BytesIO object at 0x7efddbb78e08>

The correct way of encoding and subsequently decoding an image with base64 turns out to be as follows:
import numpy as np
import cv2
import base64
cap = cv2.VideoCapture(0)
# capture frame by frame
ret, frame = cap.read()
# encode frame
encoded_string = base64.b64encode(frame)
# decode frame
decoded_string = base64.b64decode(encoded_string)
decoded_img = np.fromstring(decoded_string, dtype=np.uint8)
decoded_img = decoded_img.reshape(frame.shape)
# show decoded frame
cv2.imshow("decoded", decoded_img)

Related

How to save image in AWS Lambda function which is generated by python matplotlib?

I have the below python code. It takes .wav file as an input via postman. It is received here as a base64 string which is then decoded back from base64. The code further processes the .wav file and generates the .png image. I have to save that in AWS S3. I am facing problems in saving it to AWS S3 because the file that is saved there does not open. It says photo viewer doesn't support this file format. Any idea how to do this?
import json
import base64
import boto3
#import scipy.io.wavfile as wav
#import scipy.signal as signal
import numpy as np
from matplotlib import pyplot as plt
from scipy import signal
import shutil
import wavio
import wave
import matplotlib.pylab as plt
from scipy.signal import butter, lfilter
from scipy.io import wavfile
import scipy.signal as sps
from io import BytesIO
def lambda_handler(event, context):
s3 = boto3.client("s3")
# retrieving data from event. Which is the wave audio file
get_file_content_from_postman = event["content"]
# decoding data. Here the wava file is converted back to binary form
decoded_file_name = base64.b64decode(get_file_content_from_postman)
new_rate = 2000
# Read file
sample_rate, clip = wavfile.read(BytesIO(decoded_file_name))
# Resample data
number_of_samples = round(len(clip) * float(new_rate) / sample_rate)
clip = sps.resample(clip, number_of_samples)
#butter_bandpass_filter is another fuction
a = butter_bandpass_filter(clip, 20, 400, 2000, order=4)
filtered = 2*((a-min(a))/(max(a)-min(a)))-1
fig = plt.figure(figsize=[1,1])
ax = fig.add_subplot(212)
ax.axes.get_xaxis().set_visible(False)
ax.axes.get_yaxis().set_visible(False)
ax.set_frame_on(False)
powerSpectrum, freqenciesFound, time, imageAxis = plt.specgram(filtered, Fs=2000)
#filename is referring to the AWS Lambda /tmp directory
filename = '/tmp/' + 'image.png'
plt.savefig(filename, dpi=400, bbox_inches='tight',pad_inches=0)
s3_upload = s3.put_object( Bucket="aaa", Key="filename.png", Body=filename)
return {
'statusCode': 200,
'body': json.dumps("Executed successfully")
}
You are using put_object which means that Body is not a file name:
Body (bytes or seekable file-like object) -- Object data.
If you want to keep using put_object, then it should be:
with open(filename, 'rb') as file_obj:
s3_upload = s3.put_object( Bucket="aaa", Key="filename.png", Body=file_obj)
Or use upload_file which is more intuitive.

Decompress nifti medical image in gz format using python

I want to decompress a butch of nii.gz files in python so that they could be processed in sitk later on. When I decompress a single file manually by right-clicking the file and choosing 'Extract..', this file is then correctly interpreted by sitk (I do sitk.ReadImage(unzipped)). But when I try to decompress it in python using following code:
with gzip.open(segmentation_zipped, "rb") as f:
bindata = f.read()
segmentation_unzipped = os.path.join(segmentation_zipped.replace(".gz", ""))
with gzip.open(segmentation_unzipped, "wb") as f:
f.write(bindata)
I get error when sitk tries to read the file:
RuntimeError: Exception thrown in SimpleITK ReadImage: C:\d\VS14-Win64-pkg\SimpleITK\Code\IO\src\sitkImageReaderBase.cxx:82:
sitk::ERROR: Unable to determine ImageIO reader for "E:\BraTS19_2013_10_1_seg.nii"
Also when trying to do it a little differently:
input = gzip.GzipFile(segmentation_zipped, 'rb')
s = input.read()
input.close()
segmentation_unzipped = os.path.join(segmentation_zipped.replace(".gz", ""))
output = open(segmentation_unzipped, 'wb')
output.write(s)
output.close()
I get:
RuntimeError: Exception thrown in SimpleITK ReadImage: C:\d\VS14-Win64-pkg\SimpleITK-build\ITK\Modules\IO\PNG\src\itkPNGImageIO.cxx:101:
itk::ERROR: PNGImageIO(0000022E3AF2C0C0): PNGImageIO failed to read header for file:
Reason: fread read only 0 instead of 8
can anyone help?
No need to unzip the Nifti images, libraries such as Nibabel can handle it without decompression.
#==================================
import nibabel as nib
import numpy as np
import matplotlib.pyplot as plt
#==================================
# load image (4D) [X,Y,Z_slice,time]
nii_img = nib.load('path_to_file.nii.gz')
nii_data = nii_img.get_fdata()
fig, ax = plt.subplots(number_of_frames, number_of_slices,constrained_layout=True)
fig.canvas.set_window_title('4D Nifti Image')
fig.suptitle('4D_Nifti 10 slices 30 time Frames', fontsize=16)
#-------------------------------------------------------------------------------
mng = plt.get_current_fig_manager()
mng.full_screen_toggle()
for slice in range(number_of_slices):
# if your data in 4D, otherwise remove this loop
for frame in range(number_of_frames):
ax[frame, slice].imshow(nii_data[:,:,slice,frame],cmap='gray', interpolation=None)
ax[frame, slice].set_title("layer {} / frame {}".format(slice, frame))
ax[frame, slice].axis('off')
plt.show()
Or you can Use SimpleITK as following:
import SimpleITK as sitk
import numpy as np
# A path to a T1-weighted brain .nii image:
t1_fn = 'path_to_file.nii'
# Read the .nii image containing the volume with SimpleITK:
sitk_t1 = sitk.ReadImage(t1_fn)
# and access the numpy array:
t1 = sitk.GetArrayFromImage(sitk_t1)

How can I resize image with quality without saving image in Python?

I use this code but it need to save
from PIL import Image
import requests
from io import BytesIO
response = requests.get(url)
img = Image.open(BytesIO(response.content))
image = img.resize((W, H), Image.ANTIALIAS)
image.save('De7k.jpeg', optimize=True, quality=Quality)
If you would like to "save" the file while keeping it in memory instead of writing a file to disk, you can write it to another BytesIO object.
from PIL import Image
import requests
from io import BytesIO
response = requests.get(url)
img = Image.open(BytesIO(response.content))
image = img.resize((W, H), Image.ANTIALIAS)
output = BytesIO()
image.save(output, format="JPEG", optimize=True, quality=Quality)

Sending matplotlib image to pymsteams (cannot create new tag pymsteams)

I am using matplotlib to plot my image.
import pandas as pd
from matplotlib import pyplot as plt
x = ['09:30', '09:33', '09:40', '09:43', '09:50', '09:53', '10:00', '10:03', '10:10', '10:13']
y = ['3010.910000', '3011.650000', '3009.130000', '3011.500000', '3010.460000', '3010.950000', '3012.830000', '3013.120000', '3011.730000', '3010.130000']
matrix = pd.DataFrame({'Time': x, 'Quote': y})
matrix['Quote'] = matrix['Quote'].astype(float)
plt.plot('Time', 'Quote', data=matrix, color='mediumvioletred')
Here is the challenge now:
import pymsteams
web_hook = 'My Microsoft Teams URL https://outlook.office.com/webhook/blahblah'
teams_message = pymsteams.connectorcard(web_hook)
msg_section = pymsteams.cardsection()
msg_section.title('Title')
msg_section.addImage(image) #I want to add that plt image here
teams_message.addSection(msg_section)
teams_message.text("Some Message")
self.teams_message.send()
I have tried this (and I want this approach, using cache):
buf = io.BytesIO()
plt.savefig(buf, format='png')
buf.seek(0)
msg_section.addImage(buf.read())
I did try saving the image to local drive 'c:/temp/'. The code did not give any error msg, but the image on Teams was a blank image, even though the image is correct in c:/temp
In summary. A PNG image has to be converted to base64 string.
Please see the example below.
Note that I'm using Python 3.6.
Additionally image width seems to be limited in a Connector Card.
import numpy as np
import matplotlib.pyplot as plt
import base64
from io import BytesIO
import pymsteams
# generate fig
fig, ax = plt.subplots(1,1,figsize=(20,6))
ax.hist(np.random.normal(0, 1, 1000), bins=51, edgecolor='k', alpha=0.5);
buf = BytesIO()
fig.savefig(buf, format="png")
# get base64 string
data = base64.b64encode(buf.getbuffer()).decode("ascii")
encoded_fig = f"data:image/png;base64,{data}"
# send encoded_fig via webhook
web_hook = 'YOUR_WEBHOOK'
teams_message = pymsteams.connectorcard(web_hook)
msg_section = pymsteams.cardsection()
msg_section.title('Title')
msg_section.addImage(encoded_fig) #I want to add that plt image here
teams_message.addSection(msg_section)
teams_message.text("Some Message")
teams_message.send()
image_file = open('img/icon.png'), "rb").read()
ICON = "data:image/png;base64,{data}".format(data=b64encode(image_file).decode("ascii"))
#And in your Teams alert creation, you call:
section.activityImage(ICON)

cv2 imdecode returns none with base64 string

When i try to convert base64 string into image i am getting none in CV2.
Following is my code
import cv2
import numpy as np
def bsae62toimage(imgvalue):
imge = "R0lGODlhEAAQAMQAAORHHOVSKudfOulrSOp3WOyDZu6QdvCchPGolfO0o/XBs/fNwfjZ0frl3/zy7////wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAkAABAALAAAAAAQABAAAAVVICSOZGlCQAosJ6mu7fiyZeKqNKToQGDsM8hBADgUXoGAiqhSvp5QAnQKGIgUhwFUYLCVDFCrKUE1lBavAViFIDlTImbKC5Gm2hB0SlBCBMQiB0UjIQA7"
nparr = np.fromstring(imge,np.uint8)
print(nparr.shape)
img1 = cv2.imdecode(nparr,cv2.IMREAD_UNCHANGED)
print(img1.shape)
It is printing the numpy array but cv2.imdecode is returning None. Can you help me to find the problem in my code?
My Findings: np.fromstring it returns 1D array. I assume it should it should return 3D array. But i may be wrong.
Since it is unclear as from where have you obtained the imge = "R0lGODlhEA..." variable. I would present an ideal flow for converting OpenCV image to base64 string and converting it back to OpenCV img as:
import cv2
import base64
import numpy as np
def to_base64(img):
_, buf = cv2.imencode(".png", img)
return base64.b64encode(buf)
def from_base64(buf):
buf_decode = base64.b64decode(buf)
buf_arr = np.fromstring(buf_decode, dtype=np.uint8)
return cv2.imdecode(buf_arr, cv2.IMREAD_UNCHANGED)
img = cv2.imread("/path/to/img.png")
img_base64 = to_base64(img)
img_decoded = from_base64(img_base64)
print img_decoded.shape
Also the documentation states that:
If the buffer is too short or contains invalid data, the empty
matrix/image is returned.
It seems to me that imge = "R0lGODlhEA..." is invalid.

Resources