python-kivy show images by data stored in a variable - python

i there is there any way like that shown in the below,
from kivy.uix.image import Image
from kivy.uix.gridlayout import GridLayout
root=GridLayout(cols=2)
image="all image data as a string"
image=Image(source=image)
root.add_widget(image)
runTouchApp(root)
i tried this but it takes only image path
why i do like this because iam doing an app so that the image data as a string stored in database and i want to display that image without storing it in device storage

You can try wrapping the data in a BytesIO object and passing this as source, if it doesn't work (can't test right now) you should be able to do so with core.image.Image (https://kivy.org/doc/stable/api-kivy.core.image.html) and then use this image's texture attribute to assign to an kivy.uix.image.Image instance.
edit: here is an example of loading an image from memory, here using pillow to construct it and get it as a BytesIO object, but you could get that source data from your database all the same
from io import BytesIO
from pathlib import Path
from kivy.app import App
from kivy.core.image import Image as CoreImage
from kivy.uix.image import Image
# NOTE this import is important to ensure kivy is ready to load an image from memory
from kivy.core.window import Window
from PIL import Image as PillowImage, ImageDraw
WIDTH = 1000
class Application(App):
def build(self):
# create a pillow image
pillow_image = PillowImage.new(mode='RGBA', size=(WIDTH, WIDTH))
draw = ImageDraw.Draw(pillow_image)
for x in range(0, WIDTH, 5):
draw.line((0, x, x, WIDTH), fill=(x, x, x, 255))
draw.line((x, WIDTH, WIDTH, WIDTH - x), fill=(x, x, x, 255))
draw.line((WIDTH, WIDTH - x, WIDTH - x, 0), fill=(x, x, x, 255))
draw.line((WIDTH - x, 0, 0, x), fill=(x, x, x, 255))
# create bytes from the image data
image_bytes = BytesIO()
pillow_image.save(image_bytes, format='png')
image_bytes.seek(0)
# load image data in a kivy texture
core_image = CoreImage(image_bytes, ext='png')
texture = core_image.texture
img = Image(texture=texture)
return img
if __name__ == "__main__":
Application().run()

You can use the image data to create a Texture and then assign that Texture to the Image. See the documentation for Texture and Image.

Related

Why do I get two different results from the same code?

I'm wondering why I am getting two different results from this code that I am using from github. If I run the compiled package on my cell phone, I get a barcode readout of 991245243. However if I use my computer, the readout is 0991245243. Can anyone explain why?
What I am trying to do is have the results from the barcode scanner check against a spreadsheet and then return the results from the adjacent cells. I want to look for exact matches because it could be catastrophic if multiple results are found and they conflict.
# Kivy OpenCV Barcode Scanner
# done by Vijeth P H
from kivy.app import App
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.uix.image import Image
from kivy.uix.widget import Widget
from kivy.uix.label import Label
from kivy.uix.button import Button
from kivy.uix.togglebutton import ToggleButton
from kivy.uix.boxlayout import BoxLayout
from kivy.clock import Clock
from kivy.graphics.texture import Texture
from pyzbar import pyzbar
import webbrowser
import cv2
# Create global variables, for storing and displaying barcodes
outputtext=''
weblink=''
leb=Label(text=outputtext,size_hint_y=None,height='48dp',font_size='45dp')
found = set() # this will not allow duplicate barcode scans to be stored
togglflag=True
class MainScreen(BoxLayout):
# first screen that is displayed when program is run
def __init__(self,**kwargs):
super().__init__(**kwargs)
self.orientation='vertical' # vertical placing of widgets
self.cam=cv2.VideoCapture(0) # start OpenCV camera
self.cam.set(3,1280) # set resolution of camera
self.cam.set(4,720)
self.img=Image() # Image widget to display frames
# create Toggle Button for pause and play of video stream
self.togbut=ToggleButton(text='Pause',group='camstart',state='down',size_hint_y=None,height='48dp',on_press=self.change_state)
self.but=Button(text='Stop',size_hint_y=None,height='48dp',on_press=self.stop_stream)
self.add_widget(self.img)
self.add_widget(self.togbut)
self.add_widget(self.but)
Clock.schedule_interval(self.update,1.0/30) # update for 30fps
# update frame of OpenCV camera
def update(self,dt):
if togglflag:
ret, frame = self.cam.read() # retrieve frames from OpenCV camera
if ret:
buf1=cv2.flip(frame,0) # convert it into texture
buf=buf1.tostring()
image_texture=Texture.create(size=(frame.shape[1],frame.shape[0]),colorfmt='bgr')
image_texture.blit_buffer(buf,colorfmt='bgr',bufferfmt='ubyte')
self.img.texture=image_texture # display image from the texture
barcodes = pyzbar.decode(frame) # detect barcode from image
for barcode in barcodes:
(x, y, w, h) = barcode.rect
cv2.rectangle(frame, (x, y), (x + w, y + h), (0, 0, 255), 2)
barcodeData = barcode.data.decode("utf-8")
barcodeType = barcode.type
weblink=barcodeData
text = "{} ({})".format(barcodeData, barcodeType)
cv2.putText(frame, text, (x, y - 10),cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 0, 255), 2)
if barcodeData not in found: # check if detected barcode is a duplicate
outputtext=text
leb.text=outputtext # display the barcode details
found.add(barcodeData)
self.change_screen()
key = cv2.waitKey(1) & 0xFF
if key == ord("q"):
cv2.destroyAllWindows()
exit(0)
# change state of toggle button
def change_state(self,*args):
global togglflag
if togglflag:
self.togbut.text='Play'
togglflag=False
else:
self.togbut.text='Pause'
togglflag=True
def stop_stream(self,*args):
self.cam.release() # stop camera
def change_screen(self,*args):
main_app.sm.current='second' # once barcode is detected, switch to second screen
class SecondScreen(BoxLayout):
def __init__(self,**kwargs):
super().__init__(**kwargs)
self.orientation='vertical'
self.lab1=Label(text='Output: ',size_hint_y=None,height='48dp',font_size='45dp')
self.but1=Button(text='Open in Web Browser',on_press=self.open_browser,size_hint_y=None,height='48dp')
self.add_widget(self.lab1)
self.add_widget(leb)
self.add_widget(self.but1)
def open_browser(self,*args):
webbrowser.open(weblink) # this opens link in browser
class TestApp(App):
def build(self):
self.sm=ScreenManager() # screenmanager is used to manage screens
self.mainsc=MainScreen()
scrn=Screen(name='main')
scrn.add_widget(self.mainsc)
self.sm.add_widget(scrn)
self.secondsc=SecondScreen()
scrn=Screen(name='second')
scrn.add_widget(self.secondsc)
self.sm.add_widget(scrn)
return self.sm
if __name__ == '__main__':
main_app=TestApp()
main_app.run()
cv2.destroyAllWindows()
Here is a picture as requested.
As the behaviors of the reader on the two platforms differ, and the decoding is wrong, one can suspect a bug in the reader that causes access to uninitialized memory. (If the problem was just a misread, not a bug, the texts would be strictly identical.)
Or can it be that the text display clips off the first character on the phone ?
Update:
The new information that on one platform the code is said to be an EAN13 and on the other a UPC-A explains the extra 0. (You should have said it upfront.) The two barcode standards require a slight difference in the way the number is reported.
But this does not explain why the code is completely wrong and why different symbologies are reported. (Maybe the default settings are different on the two patforms.)

Click screenshot of part of the screen using python kivy

At the moment the below code shows a camera layout using laptop webcam just fine - I want to show a rectangle frame within the camera window - user will hold a book aligned to the frame and I need to capture an image of the book i.e capture image of the part within the frame. I am struggling to
Show a transparent rectangle as a frame (this is inside a boxlayout inside a camera floatlayout)
Grab an image of only the part within the frame
There is a button below the camera layout at click of which the image will be saved to a folder on the machine
Please can somebody guide me how to proceed and whether this can be achieved in any other way using any other module
import kivy
from PIL import ImageGrab
from kivy.uix.boxlayout import BoxLayout
from numpy import shape
kivy.require('1.7.2')
from kivy.app import App
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.camera import Camera
from kivy.uix.button import Button
from kivy.core.window import Window
from kivy.graphics import Color, Rectangle
class CamApp(App):
# Function to take a screenshot
def screengrab(self, *largs):
im2 = ImageGrab.grab(bbox=None)
im2.show()
#outname = self.fileprefix + '_%(counter)04d.png'
#Window.screenshot(name=outname)
def build(self):
# create a floating layout as base
camlayout = FloatLayout(size=(600, 600))
cam = Camera() # Get the camera
cam = Camera(resolution=(1024, 1024), size=(300, 300))
cam.play = True # Start the camera
camlayout.add_widget(cam)
boxlayout = BoxLayout(id='imageBox', size_hint=[0.5, 0.7], pos_hint={'center_x': .5, 'center_y': .5})
boxlayout.bind(size=self.update_rect, pos=self.update_rect)
with boxlayout.canvas.before:
#Color(0, 1, 0, 1) # green; colors range from 0-1 instead of 0-255
self.rect = Rectangle(size=boxlayout.size,
pos=boxlayout.pos, outline='black')
camlayout.add_widget(boxlayout)
button = Button(text='Take Picture', size_hint=(0.12, 0.12))
button.bind(on_press=self.screengrab)
camlayout.add_widget(button) # Add button to Camera Layout
self.fileprefix = 'snap'
return camlayout
def update_rect(self,instance, value):
self.rect.pos = instance.pos
self.rect.size = instance.size
if __name__ == '__main__':
CamApp().run()
Click to see output
In kivy, the Color() function takes arguments representing RGBA. That means the last argument is alpha, and passing it a float will make it transparent.
So while Color(0, 1, 0, 1) is a solid color, Color(0, 1, 0, .5) will be semitransparent.
As for grabbing an image of only part of the frame, you might consider grabbing the whole frame, then using PIL to crop the image with
from PIL import Image
im = Image.open(r"C:\path\to\picture\my_screenshot.png")
im.crop((left, top, right, bottom))
Just replace left, top, right, and bottom with the dimensions you want to cut out.

PIL ImageTk AttributeError, can't display ImageTk on window

I've been working on a small program to convert PNG, JPG and JPEG files to .ICO files. This was relatively simple to do, but while I was trying to display the selected PNG image in Tkinter using PIL's ImageTk, I get a strange error.
from tkinter import *
from tkinter import filedialog
import re
from PIL import Image, ImageTk
root = Tk()
pathToImage = ''
selectedImage = ''
def make_square(im, min_size=256, fill_color = (0, 0, 0)): # Puts the selected image into a black square
x, y = im.size
size = max(min_size, x, y)
new_im = Image.new('RGB', (size,size), fill_color)
new_im.paste(im, (int((size - x) / 2), int((size - y) / 2)))
return new_im
def select_image(): # Function that is run when Select PNG button is clicked
global pathToImage
pathToImage = filedialog.askopenfilename(filetypes=[('PNG Files','*.png'),('JPG Files','*.jpg'),('JPEG Files','*.jpeg')]) # Gets path to PNG, JPG or JPEG image
image = Image.open(pathToImage) # Opens image in PIL
image = make_square(im=image) # Turns image into square for ICO conversion
#!!!!!!!!!!!!!!!!!!!!! ERROR Among these 3 lines
global selectedImage # Here I try to tell Python I'm referring to the global variable selectedImage
selectedImage = (ImageTk.PhotoImage(image=pathToImage)) # selectedImage is given the value of ImageTk.PhotoImage with the source image being the path of the selected image
Label(root, image=selectedImage).pack() # Throws an error for some reason
# Rest of the code works fine
image.save('output.ico')
Label(root,text='Converted file stored in the same folder as \'PNG to ICO.py\'').pack()
Button(root,text='Select PNG', command=select_image).pack()
root.mainloop()
I've tried saving the image to display to a variable, but that doesn't seem to work either. Could anyone help point out what I did wrong? I'd really appreciate it.
There are couple of issues with your code.
In your line (ImageTk.PhotoImage(image=pathToImage)) you are passing a path (str) which is not what it should take, ImageTk.PhotoImage takes instance of Image(path). So change it to the image getting returned by make_square function.
Every time when the button is clicked, it'll create a new label if that's what you want then ignore this, if not then create your labels outside of the function select_image after you create the Button and later in the function update them.
I don't really get why you are using global when you can achieve your purpose without making variables pathToImage or selectedImage unless you want to access that image later in the program.
Here is the improved version of your code.
from tkinter import *
from tkinter import filedialog
import re
from PIL import Image, ImageTk
def make_square(im, min_size=256, fill_color = (0, 0, 0)): # Puts the selected image into a black square
x, y = im.size
size = max(min_size, x, y)
new_im = Image.new('RGB', (size,size), fill_color)
new_im.paste(im, (int((size - x) / 2), int((size - y) / 2)))
return new_im
def select_image(): # Function that is run when Select PNG button is clicked
pathToImage = filedialog.askopenfilename(filetypes=[('PNG Files','*.png'),('JPG Files','*.jpg'),('JPEG Files','*.jpeg')])
image = Image.open(str(pathToImage)) # Opens image in PIL
image = make_square(im=image) # Turns image into square for ICO conversion
selectedImage = ImageTk.PhotoImage(image=image)
imglabel.img = selectedImage # create a reference of the image
imglabel['image'] = selectedImage
# selectedImage is given the value of ImageTk.PhotoImage with the source image being the path of the selected image
# Rest of the code works fine
image.save('output.ico', 'ICO')
infolabel['text'] = 'Converted file stored in the same folder as \'PNG to ICO.py\''
root = Tk()
but1 = Button(root,text='Select PNG', command=select_image)
but1.pack()
imglabel = Label(root)
imglabel.pack()
infolabel = Label(root)
infolabel.pack()
root.mainloop()

Kivy-python: duplicate image on texture

I am developing app in python 3.6 with kivy.
I'd like to display an image saved as numpy array.
I wrote this code:
from kivy.app import App
from kivy.uix.image import Image
from kivy.uix.widget import Widget
from kivy.graphics.texture import Texture
import cv2
class Test(Widget):
def __init__(self, **kwargs):
super(Test, self).__init__(**kwargs)
img = cv2.imread(r'./kulki.jpg', cv2.IMREAD_GRAYSCALE)
w, h = img.shape
texture = Texture.create(size=(h, w))
texture.blit_buffer(img.flatten(), colorfmt='rgb', bufferfmt='ubyte')
w_img = Image(size=(w, h), texture=texture)
self.add_widget(w_img)
class DemoApp(App):
def build(self):
return Test()
if __name__ == '__main__':
DemoApp().run()
and this is my output:
for this image:
Does anybody know why there are several of the same pictures instead of one? Anw why do I have to change dimensions in places (w,h) -> (h,w)?
Best regards!
I think the problem is that you are converting the image to grayscale when you read it, then your are using rgb for the Texture color format. If you make those two agree, then your code will work. For example, change:
texture.blit_buffer(img.flatten(), colorfmt='rgb', bufferfmt='ubyte')
to:
texture.blit_buffer(img.flatten(), colorfmt='luminance', bufferfmt='ubyte')

Load image in tkinter from pygame surface in python 3

I would like to load an image in tkinter from a pygame surface and I am having a problem.
This is what I am currently trying:
image= pygame.image.tostring(surf, 'RGB')
tkimage= tkinter.PhotoImage(data= image)
canvas.create_image(0, 0, tkimage)
but I unfortunately get this error:
_tkinter.TclError: couldn't recognize image data
The PhotoImage class can only read GIF and PGM/PPM files, either directly from a file or as base64 encoded string.
You should use the Python Imaging Library for loading and creating the image for Tk.
Here's an example:
import pygame
from PIL import Image
import ImageTk
import Tkinter
# load image in pygame
pygame.init()
surf = pygame.image.load('bridge.png')
# export as string / import to PIL
image_str = pygame.image.tostring(surf, 'RGB') # use 'RGB' to export
w, h = surf.get_rect()[2:]
image = Image.fromstring('RGB', (w, h), image_str) # use 'RGB' to import
# create Tk window/widgets
root = Tkinter.Tk()
tkimage = ImageTk.PhotoImage(image) # use ImageTk.PhotoImage class instead
canvas = Tkinter.Canvas(root)
canvas.create_image(0, 0, image=tkimage)
canvas.pack()
root.mainloop()
------- UPDATE ------
import pygame
from pygame.locals import *
from PIL import Image
import ImageTk
import Tkinter
# load image in pygame
pygame.init()
surf = pygame.image.load('pic_temp.png') # you can use any Surface a Camers is also an Surface
mode = "RGB"
# export as string / import to PIL
image_str = pygame.image.tostring(surf, mode) # use 'RGB' to export
size = (640, 480)
#image = Image.fromstring(mode, size, image_str)
# use frombuffer() - fromstring() is no longer supported
image = Image.frombuffer(mode, size, image_str, 'raw', mode, 0, 1) # use 'RGB' to import
# create Tk window/widgets
root = Tkinter.Tk()
tkimage = ImageTk.PhotoImage(image) # use ImageTk.PhotoImage class instead
label = Tkinter.Label(root, image=tkimage)
label.pack()
root.mainloop()

Categories