Decode video frame encoded by Python to display in Node based webapp - node.js

I use Python 3 and OpenCV to read video and send the frames to a Node.js based web page via socket.
Let's imagine something like this:
cap = cv2.VideoCapture(video_path)
while cap.isOpened():
ret, frame = cap.read()
send(frame)
In the send() function, before actually sending, I pass the frame into a normalize() function to convert it to deliverable format for socket IO. The normalize() looks like below:
def normalize(frame):
d = frame.flatten()
s = d.tostring()
b = b64encode(s)
return b.decode('ascii')
The data was sent as well. In Node.js app, I receive something as below:
How I can convert this encoded string to normal video, or even image?
Thanks.

To encode an image, use cv2.imencode(). Then you can write that buffer into a base 64 string, and then display that directly with HTML or whatever you want to do with it.
Here's a basic example. First, the Python:
import cv2
import base64
def encode_img(img):
"""Encodes an image as a png and encodes to base 64 for display."""
success, encoded_img = cv2.imencode('.png', img)
if success:
return base64.b64encode(encoded_img).decode()
raise ValueError("unable to encode image")
That will give you the encoded image in base 64. The string that this returns can be displayed directly with HTML by using the string as the src of an image if you prepend data:image/png;base64, to it.
So for example...
import numpy as np
img = np.uint8(255 * np.random.rand(50, 50))
encoded_img = encode_img(img)
b64_src = 'data:image/png;base64,'
img_src = b64_src + encoded_img
With this random image my img_src becomes:
'data:image/png;base64,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'
Then in a simple HTML file, use this as the image tag's source:
<html>
<body>
<img src="data:image/png;base64,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">
</body>
</html>
You should be able to see the image.
You can also save these directly as images on your node server with this format. You can use fs.writeFile() in for e.g. to write this b64 string directly to an image file, by specifying an options object with {encoding: 'base64'}. For example, from this tutorial:
import fs from 'fs';
fs.writeFile('image.png', base64Image, {encoding: 'base64'}, function(err) {
console.log('File created');
});
Of course if you're using other libraries in node to play with the images, you'll need to use some function from that library to decode the images. Probably not too hard to exchange from b64 to bytes, but you'll need to decode those bytes into an image from whatever libs you're using server-side.

Related

Passing base64 .docx to docx.Document results in BadZipFile exception

I'm writing an Azure function in Python 3.9 that needs to accept a base64 string created from a known .docx file which will serve as a template. My code will decode the base64, pass it to a BytesIO instance, and pass that to docx.Document(). However, I'm receiving an exception BadZipFile: File is not a zip file.
Below is a slimmed down version of my code. It fails on document = Document(bytesIODoc). I'm beginning to think it's an encoding/decoding issue, but I don't know nearly enough about it to get to the solution.
from docx import Document
from io import BytesIO
import base64
var = {
'template': 'Some_base64_from_docx_file',
'data': {'some': 'data'}
}
run_stuff = ParseBody(body=var)
output = run_stuff.run()
class ParseBody():
def __init__(self, body):
self.template = str(body['template'])
self.contents = body['data']
def _decode_template(self):
b64Doc = base64.b64decode(self.template)
bytesIODoc = BytesIO(b64Doc)
document = Document(bytesIODoc)
def run(self):
self.document = self._decode_template()
I've also tried the following change to _decode_template and am getting the same exception. This is running base64.decodebytes() on the b64Doc object and passing that to BytesIO instead of directly passing b64Doc.
def _decode_template(self):
b64Doc = base64.b64decode(self.template)
bytesDoc = base64.decodebytes(b64Doc)
bytesIODoc = BytesIO(bytesDoc)
I have successfully tried the following on the same exact .docx file to be sure that this is possible. I can open the document in Python, base64 encode it, decode into bytes, pass that to a BytesIO instance, and pass that to docx.Document successfully.
file = r'WordTemplate.docx'
doc = open(file, 'rb').read()
b64Doc = base64.b64encode(doc)
bytesDoc = base64.decodebytes(b64Doc)
bytesIODoc= BytesIO(bytesDoc)
newDoc = Document(bytesIODoc)
I've tried countless other solutions to no avail that have lead me further away from a resolution. This is the closest I've gotten. Any help is greatly appreciated!
The answer to the question linked below actually helped me resolve my own issue. How to generate a DOCX in Python and save it in memory?
All I had to do was change document = Document(bytesIODoc) to the following:
document = Document()
document.save(bytesIODoc)

Why saving Image object is not the same for thumbnail() and resize()?

from PIL import Image, ImageEnhance, ImageFilter
image = "Ash and Pikachu.png"
image = Image.open(image)
images = image.thumbnail((400, 320)) # thumbnail() works by changing the var name
# image = image.thumbnail((400, 320)) # gives error by keeping same var name
image.save("NewImage.png")
The above code will convert the image to thumbnail as expected. But by replacing thumbnail() with resize(), it just copies and saves the source image with new name.
from PIL import Image, ImageEnhance, ImageFilter
image = "Ash and Pikachu.png"
image = Image.open(image)
# images = image.thumbnail((400, 320)) # doesn't throw errors but doesn't resize the image
image = image.resize((400, 320)) # resize() works by keeping same var name
image.save("NewImage.png")
I'm not using both at the same time, but just wanted to point out where I'm facing issues. Anyhow, can I use the same code to save images in both thumbnail() and resize()?
Let's see the documentation on Image.thumbnail:
Note that this function modifies the Image object in place.
And, the documentation on Image.resize states:
Returns a resized copy of this image.
So, the correct usage of both methods including saving looks like this:
from PIL import Image
image = Image.open('path/to/your/image.png')
image.thumbnail((200, 200))
image.save('thumbnail.png')
image = Image.open('path/to/your/image.png')
image = image.resize((200, 200))
image.save('resize.png')
Both save a (200, 200) version of the input image. Notice: There's no reassignment of image in the first case, but in the second. That's in line with your codes. Inspect images in your first case, it's no proper Image object (it's None actually), but saving image still works, because Image.thumbnail worked in place. In your second case, you explicitly reassign image, which is correct here.
----------------------------------------
System information
----------------------------------------
Platform: Windows-10-10.0.16299-SP0
Python: 3.8.5
Pillow: 8.0.1
----------------------------------------

Saving (.svg) images using Scrapy

Im using Scrapy and I want to save some of the .svg images from the webpage locally on my computer. The urls for these images have the structure '__.com/svg/4/8/3/1425.svg' (and is a full working url, https included).
Ive defined the item in my items.py file:
class ImageItem(scrapy.Item):
image_urls = scrapy.Field()
images = scrapy.Field()
Ive added the following to my settings:
ITEM_PIPELINES = {
'scrapy.pipelines.images.ImagesPipeline': 1,
}
IMAGES_STORE = '../Data/Silks'
MEDIA_ALLOW_REDIRECTS = True
In the main parse function im calling:
imageItem = ImageItem()
imageItem['image_urls'] = [url]
yield imageItem
But it doesn't save the images. Ive followed the documentation and tried numerous things but keep getting the following error:
StopIteration: <200 https://www.________.com/svg/4/8/3/1425.svg>
During handling of the above exception, another exception occurred:
......
......
PIL.UnidentifiedImageError: cannot identify image file <_io.BytesIO object at 0x1139233b0>
Am I missing something? Can anyone help? I am fully stumped.
Gallaecio was right! Scrapy was having an issue with the .svg file type. Changed the imagePipeline to the filePipeline and it works!
For anyone stuck the documentation is here
Python Imaging Library (PIL), which is used by the ImagesPipeline, does not support vector images.
If you still want to benefit from the ImagesPipeline capabilities and not switch to the more general FilesPipeline, you can do something along those lines
from svglib.svglib import svg2rlg
from reportlab.graphics import renderPM
from io import BytesIO
class SvgCompatibleImagesPipeline(ImagesPipeline):
def get_images(self, response, request, info, *, item=None):
"""
Add processing of SVG images to the standard images pipeline
"""
if isinstance(response, scrapy.http.TextResponse) and response.text.startswith('<svg'):
b = BytesIO()
renderPM.drawToFile(svg2rlg(BytesIO(response.body)), b, fmt='PNG')
res = response.replace(body=b.getvalue())
else:
res = response
return super().get_images(res, request, info, item=item)
This will replace the SVG image in the response body by a PNG version of it, which can be further processed by the regular ImagesPipeline.

Opening Image from Website

I was trying to make a simple program to pull an image from the website xkcd.com, and I seem to be running into a problem where it returns list object has no attribute show. Anyone know how to fix this?
import requests
from lxml import html
r = requests.get("http://imgs.xkcd.com/comics/self_driving_issues.png")
tree = html.fromstring(r.content)
final = tree.xpath("""//*[#id="comic"]/img""")
final.show()
Your call to requests.get is retrieving the actual image, the byte code for the png. There is no html to parse or search for with xpath.
Note here, the content is bytes:
r = requests.get("http://imgs.xkcd.com/comics/self_driving_issues.png")
print(r.content)
b'\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x02\xe4\x00\x00\x01#\x08\x03\x00\x00\x00M\x7f\xe4\xc6\x00\x00\x00\x04gAMA\x00\x00\xb1\x8f
Here you see that you can save the results directly to disk.
import requests
r = requests.get("http://imgs.xkcd.com/comics/self_driving_issues.png")
with open("myimage.png", "wb") as f:
f.write(r.content)
[Edit] And to Show the image (you will need to install pillow.)
import requests
from PIL import Image
import io
r = requests.get("http://imgs.xkcd.com/comics/self_driving_issues.png")
img = Image.open(io.BytesIO(r.content))
img.show()

How to upload an image with flask and store in couchdb?

A previous question asks how to retrieve at attachment from couchdb and display it in a flask application.
This question asks how to perform the opposite, i.e. how can an image be uploaded using flask and saved as a couchdb attachment.
Take a look at the example from WTF:
from werkzeug.utils import secure_filename
from flask_wtf.file import FileField
class PhotoForm(FlaskForm):
photo = FileField('Your photo')
#app.route('/upload/', methods=('GET', 'POST'))
def upload():
form = PhotoForm()
if form.validate_on_submit():
filename = secure_filename(form.photo.data.filename)
form.photo.data.save('uploads/' + filename)
else:
filename = None
return render_template('upload.html', form=form, filename=filename)
Take a look at the FileField api docs. There you have a stream method giving you access to the uploaded data. Instead of using the save method as in the example you can access the bytes from the stream, base64 encode it and save as an attachment in couchdb, e.g. Using put_attachment. Alternatively, the FileStorage api docs suggest you can use read() to retrieve the data.

Resources