-1

I've searched about it and found "scatter", but scatter use for image. I want to zoom it with live camera.

Anyone know how can I do that?

This is code example I've written, but it doesn't work.

from kivy.app import App
from kivy.uix.widget import Widget
from kivy.lang import Builder
from kivy.properties import ObjectProperty
from kivy.uix.screenmanager import ScreenManager , Screen
from kivy.uix.image import Image
from kivy.core.window import Window
from kivy.base import runTouchApp
from kivymd.app import MDApp
from kivy.uix.boxlayout import BoxLayout
import time
from kivy.core.window import Window
from kivy.uix.camera import Camera
from kivy.uix.scatter import Scatter
from kivy.uix.relativelayout import RelativeLayout
from kivy.properties import NumericProperty


Window.size = (1600, 850)

class MyCamera(Camera):
    
    region_x = NumericProperty(0)
    region_y = NumericProperty(0)
    region_w = NumericProperty(1600)
    region_h = NumericProperty(850)
    
    def on_text(self,camera):
        self.texture = texture = camera.texture
        
        self.texture = self.texture.get_region(self.region_x, self.region_y, self.region_w, self.region_h)
        self.texture_size = list(texture.size)
        self.canvas.ask_update()



class MainPage(Screen):
    pass

class WindowManager(ScreenManager):
    pass


class CameraClick(Screen):
    scale = NumericProperty(1)


    def on_touch_down(self, touch):
        if touch.is_mouse_scrolling:
            if touch.button == 'scrolldown':
                print("down")
                if self.scale <10:
                    self.scale *= 1.1
                    self.ids['camera'].region_w /= 1.1
                    self.ids['camera'].region_h /= 1.1
                    self.ids['camera'].region_x = (1600-self.ids['camera'].region_w) // 2
                    self.ids['camera'].region_y = (850-self.ids['camera'].region_h) // 2 
    
    
            elif touch.button == 'scrollup':
                print("up")
                if self.scale >1:
                    self.scale *= 0.8
                    
                    self.ids['camera'].region_w /= 0.8
                    self.ids['camera'].region_h /= 0.8
                    if(self.ids['camera'].region_w > 1600) or (self.ids['camera'].region_h >850):
                        self.ids['camera'].region_w = 1600
                        self.ids['camera'].region_h = 850
                        
                        
                    self.ids['camera'].region_x = (1600-self.ids['camera'].region_w) //2
                    self.ids['camera'].region_y = (850-self.ids['camera'].region_h) //2
                
    
    def capture(self):
        camera = self.ids['camera']
        timestr = time.strftime("%Y%m%d_%H%M%S")
        camera.export_to_png("IMG_{}.png".format(timestr))
        print("Captured")

    
            

Builder.load_string("""

#:import utils kivy.utils
<WindowManager>:
    MainPage:
    CameraClick:
    
          

<MainPage>:
    name: "main page"
                 
    BoxLayout:
        cols:1
        orientation: "horizontal"
        size: root.width , root.height
        spacing: 25
        padding: 530, 900 , 900 , 260

        Button:
            text: "take a picture"
            color: (200,250,210)
            font_size: 40
            size_hint_x: 1
            height:60
            size_hint_y: None
            width:500
            on_release: app.root.current = "camera"

                              
<CameraClick>:

    name: "camera"
    orientation: 'vertical'    
    
    MyCamera:
        id: camera
        play: True
        allow_stretch: True
        resolusion: (640,480)

    BoxLayout:
        orientation: 'vertical'
        padding: 100 , 10 , 800 , 590

        Button:
            text: 'play'
            size_hint_y: None
            size_hint_x: None
            height: '48dp'
            pos:200,200
            font_size:40
            width: 100
            height: 50
            on_press: camera.play = not camera.play
                
                
    BoxLayout:
        orientation: 'vertical'
        padding: 100 , 10 , 800 , 380

        Button:
            text: 'capture'
            size_hint_y: None
            size_hint_x: None
            height: '48dp'
            pos:200,200
            font_size:40
            width: 100
            height: 50
            on_press: root.capture()
 

    BoxLayout:
        orientation: 'vertical'
        padding: 100 , 10 , 800 , 200
        
        Button:
            text: 'ZOOM'
            size_hint_y: None
            size_hint_x: None
            height: '48dp'
            pos:100,100
            font_size:30
            width: 100
            height: 50
            on_press: root.on_touch_down()
            
            
    BoxLayout:
        orientation: 'vertical'
        padding: 50 , 10 , 800 , 730
    

        Button:
            text: 'HOME'
            size_hint_y: None
            size_hint_x: None
            height: '48dp'
            pos:200,200
            font_size:40
            width: 100
            height: 50
            on_release: app.root.current = "main page"
        
""")

class Shenacell(MDApp):
    def build(self):
        self.theme_cls.primary_palette = "BlueGray"
        return WindowManager()

if __name__ == '__main__' :
    Shenacell().run()
    
    

    
Makyen
  • 31,849
  • 12
  • 86
  • 121
siitaw
  • 107
  • 3
  • 12
  • first you should know how to do it without `kivy` – furas Jun 14 '21 at 11:18
  • @furas you know how can I do it ? – siitaw Jun 15 '21 at 05:35
  • I don't know but if you means hardware zoom (move lens) then it may depends on camera - so you would have to read documentation for camera. I think for some cameras you can control zoom in module `cv2`. If you means sofware zoom (resize image in memory) then you can use `cv2.resize()` for this. – furas Jun 15 '21 at 07:18
  • of couse all version will need to write code which runs loop which gets single frame and display it on screen and also check if other widget change value and it is time to zoom image. – furas Jun 15 '21 at 07:28
  • I've use raspberry's camera . and I've write a GUI for use camera . now i want to zoom in or zoom out camera . not hardware . just code – siitaw Jun 15 '21 at 07:40
  • @furas plz check my code . maybe know what I want – siitaw Jun 15 '21 at 08:30
  • you will have to write own widget `Camera` to control size of displayed image. – furas Jun 15 '21 at 20:35

1 Answers1

0

Here is source code for widget Camera.

It has method on_tex() which gets texture from real camera

def on_tex(self, camera):
    self.texture = texture = camera.texture
    self.texture_size = list(texture.size)
    self.canvas.ask_update()

texture has method get_region() which can be used to get only some part of image -

self.texture.get_region(x, y, width, height)

and this way you can create zoom effect - when you have allow_stretch: True.

Here is class which gets only some region.
I assumed that camera gives image with size 640x480 but it would need to get value from variable resolution in Camera.

class MyCamera(Camera):
    
    region_x = NumericProperty(0)
    region_y = NumericProperty(0)
    region_w = NumericProperty(640)
    region_h = NumericProperty(480)
    
    def on_tex(self, camera):
        
        self.texture = texture = camera.texture

        # get some region
        self.texture = self.texture.get_region(self.region_x, self.region_y, self.region_w, self.region_h)

        self.texture_size = list(texture.size)
        self.canvas.ask_update()

And now in CameraClick I can change values region_x, region_y, region_w, region_h to create zoom effect.

class CameraClick(Screen):

    scale = NumericProperty(1)
    
    def on_touch_down(self, touch):
        
        if touch.is_mouse_scrolling:

            if touch.button == 'scrolldown':
                print("down")
                if self.scale < 10:
                    self.scale *= 1.1

                    # scale region size
                    self.ids['camera'].region_w /= 1.1
                    self.ids['camera'].region_h /= 1.1

                    # center region
                    self.ids['camera'].region_x = (640-self.ids['camera'].region_w) // 2
                    self.ids['camera'].region_y = (480-self.ids['camera'].region_h) // 2
                    
            elif touch.button == 'scrollup':
                print("up")
                if self.scale > 1:
                    self.scale *= 0.8

                    # scale region size
                    self.ids['camera'].region_w /= 0.8
                    self.ids['camera'].region_h /= 0.8
                    if (self.ids['camera'].region_w > 640) or (self.ids['camera'].region_h > 480):
                        self.ids['camera'].region_w = 640
                        self.ids['camera'].region_h = 480

                    # center region
                    self.ids['camera'].region_x = (640-self.ids['camera'].region_w) // 2
                    self.ids['camera'].region_y = (480-self.ids['camera'].region_h) // 2

It many need changes

  • use resolution to get real camera size instead hardcoded 640,480.
  • use buttons, keyboard or mouse to move image to see other regions.

If you run code with allow_stretch: False then it gives smaller image instead of resizing it - so it would need different method. It would need to get texture, rescale it and crop to expected region.


Full working code.

EDIT:

I added Capture. It needs super().on_touch_down(touch) in on_touch_down to execute on_press,on_release, etc.

from kivymd.app import MDApp
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.uix.camera import Camera
from kivy.lang import Builder
from kivy.properties import NumericProperty
import time


class MyCamera(Camera):

    region_x = NumericProperty(0)
    region_y = NumericProperty(0)
    region_w = NumericProperty(640)
    region_h = NumericProperty(480)

    def on_tex(self, camera):

        self.texture = texture = camera.texture

        # get some region
        self.texture = self.texture.get_region(self.region_x, self.region_y, self.region_w, self.region_h)

        self.texture_size = list(texture.size)
        self.canvas.ask_update()


class WindowManager(ScreenManager):
    pass


class CameraClick(Screen):

    scale = NumericProperty(1)

    def on_touch_down(self, touch):
        #print('[DEBUG] on_touch_down')

        super().on_touch_down(touch)  # run original `Screen.on_touch_down` which runs `on_press`, `on_release`

        if touch.is_mouse_scrolling:
            if touch.button == 'scrolldown':
                print("down: (zoom in) ", self.scale)
                if self.scale < 10:
                    self.scale *= 1.1
                    # scale region size
                    self.ids['camera'].region_w /= 1.1
                    self.ids['camera'].region_h /= 1.1
                    # center region
                    self.ids['camera'].region_x = (640-self.ids['camera'].region_w) // 2
                    self.ids['camera'].region_y = (480-self.ids['camera'].region_h) // 2
                
            elif touch.button == 'scrollup':
                print("  up: (zoom out)", self.scale)
                if self.scale > 1:
                    self.scale *= 0.8
                    # scale region size
                    self.ids['camera'].region_w /= 0.8
                    self.ids['camera'].region_h /= 0.8
                    if (self.ids['camera'].region_w > 640) or (self.ids['camera'].region_h > 480):
                        self.ids['camera'].region_w = 640
                        self.ids['camera'].region_h = 480
                    # center region
                    self.ids['camera'].region_x = (640-self.ids['camera'].region_w) // 2
                    self.ids['camera'].region_y = (480-self.ids['camera'].region_h) // 2

    def capture(self):
        camera = self.ids['camera']
        filename = time.strftime("IMG_%Y%m%d_%H%M%S.png")
        camera.export_to_png(filename)
        print("Captured:", filename)


Builder.load_string("""
<WindowManager>:
    CameraClick:

<CameraClick>:
    name: "camera"
    orientation: 'vertical'
    MyCamera:
        id: camera
        play: True
        allow_stretch: True
    Button:
        text: 'Capture'
        size_hint_y: None
        size_hint_x: None
        on_press: root.capture()
""")


class Shenacell(MDApp):
    def build(self):
        return WindowManager()

if __name__ == '__main__':
    Shenacell().run()

Maybe it should be done as wrapper class which gets Camera as argument.


BTW:

If you would need to display together original image and zoomed image then you may need code from my answer for question Kivy Camera on multiple screen

furas
  • 134,197
  • 12
  • 106
  • 148
  • actually not work . just print down and up when I've zoom . but did not zoom in or zoom out in camera :( – siitaw Jun 19 '21 at 05:47
  • 1
    It works for me. I can't see how it work on your computer so I can't help. You can only use `print()` to see which line of code is excuted and what you have in variables. Maybe it need somethings else or it has wrong values. Shortly: you have to debug code and you can use `print()` for this. – furas Jun 19 '21 at 05:57
  • I've update my code . plz check it again :( @furas – siitaw Jun 19 '21 at 07:49
  • 1
    in `MyCamera` it has to be `on_tex` instead of `on_text` - and then it starts zooming but it still need some changes to zoom it correctly – furas Jun 19 '21 at 08:43
  • my camera gives image `640x480` so I have to use `640`, `480` instead of `1600`, `850` - and it doesn't matter what size has window – furas Jun 19 '21 at 08:52
  • sorry , when you click on capture button , is that work ? in my computer Its not call other method . I dont Know why – siitaw Jun 19 '21 at 11:12
  • 1
    after digging in codes I finally released that problem makes `on_touch_down`. Normally `Kivy` uses `on_touch_down` to get mouse events and run functions assigned to `on_press`, `on_release`. If you write own `on_touch_down` then it doesn't have code which runs functions assigned to `on_press`, `on_release`. In your `on_touch_down` you need to use `super().on_touch_down(touch)` to run code which will run functions assigned to `on_press`, `on_release`. I added it in answer in `Full working code`. – furas Jun 19 '21 at 23:30
  • sorry . you know how can I get video and save it ? like capture @furas – siitaw Jun 20 '21 at 08:42
  • you have to get frame by frame and save every frame in video file. I don't know if `Kivy` has functions to save video files but you can do it with `cv2.VideoWriter`. You send frame by frame (like capture after caputer) and it save it in video file. – furas Jun 20 '21 at 08:48
  • I have repo [python-examples](https://github.com/furas/python-examples) and I found example which uses `cv2` to record video from camera. [cv2/save-file](https://github.com/furas/python-examples/blob/master/cv2/save-file/main.py) – furas Jun 20 '21 at 08:54