Need help with making a document scanner/image cropper

30 views
Skip to first unread message

Xero Gaming

unread,
Sep 21, 2022, 12:01:59 PM9/21/22
to Kivy users support
I have been trying to implement document scanning into my app . 
Here is what i have done so far 
from kivy.uix.label import Label
from kivy.app import App
from kivy.uix.behaviors import DragBehavior
from kivy.lang import Builder
from kivy.uix.boxlayout import BoxLayout
# You could also put the following in your kv file...
import cv2
from kivy.core.window import Window
import numpy as np
kv = '''
<DragLabel>:
    # Define the properties for the DragLabel
    drag_rectangle: self.x, self.y, self.width, self.height
    drag_timeout: 10000000
    drag_distance: 0
    #on_touch_move: root.dragging()
    #on_touch_up: root.released()
<P1>:
    on_touch_down: app.point_1()
<P2>:
<P3>:
<P4>:

<Points>:
    size_hint: None,None
    size: 25,25

FloatLayout:
    # Define the root widget
    Image:
        source: 'resume_tilted.jpg'
        size_hint: None, None
        size_hint: 1,1
        allow_stretch: True
        keep_ratio: False

        P1:
            id: p1
        P2:
            id: p2
        P3:
            id: p3
        P4:
            id: p4
    Button:
        size: 75, 50
        size_hint: None, None
        text: "get positions"
        on_press: app.get_positions()
        pos_hint: {"x": 0 , "top":1 }
   

<Circles>:
    canvas:
        Color:
            rgb: 0,1,1
        Ellipse:
            pos: self.pos
            size: 25,25
       
'''
class Circles():
    pass

class DragLabel(DragBehavior, BoxLayout , Label):
    pass

class Points(DragLabel,Circles):
    pass

class P1(Points):
    position = None
    def on_touch_up(self, touch):
        if self.collide_point(*touch.pos):
            #print("stopped P1-------- ",touch)
            self.position = touch.pos
            return super(P1, self).on_touch_up(touch)
        else:
            return super(P1, self).on_touch_up(touch)
    def on_touch_move(self, touch):
        if self.collide_point(*touch.pos):
            #print("dragging P1------------",touch)
            return super(P1, self).on_touch_move(touch)
        else:
            return super(P1, self).on_touch_move(touch)
class P2(Points):
    position = None
    def on_touch_up(self, touch):
        if self.collide_point(*touch.pos):
            self.position = touch.pos
            #print("stopped P2-------- ",touch)
            return super(P2, self).on_touch_up(touch)
        else:
            return super(P2, self).on_touch_up(touch)
    def on_touch_move(self, touch):
        if self.collide_point(*touch.pos):
            #print("dragging P2------------",touch)
            return super(P2, self).on_touch_move(touch)
        else:
            return super(P2, self).on_touch_move(touch)
class P3(Points):
    position = None
    def on_touch_up(self, touch):
        if self.collide_point(*touch.pos):
            self.position = touch.pos
            #print("stopped P3-------- ",touch)
            return super(P3, self).on_touch_up(touch)
        else:
            return super(P3, self).on_touch_up(touch)
    def on_touch_move(self, touch):
        if self.collide_point(*touch.pos):
            #print("dragging P3------------",touch)
            return super(P3, self).on_touch_move(touch)
        else:
            return super(P3, self).on_touch_move(touch)
class P4(Points):
    position = None
    def on_touch_up(self, touch):
        if self.collide_point(*touch.pos):
            self.position = touch.pos
            #print("stopped P4-------- ",touch)
            return super(P4, self).on_touch_up(touch)
        else:
            return super(P4, self).on_touch_up(touch)
    def on_touch_move(self, touch):
        if self.collide_point(*touch.pos):
            #print("dragging P4------------",touch)
            return super(P4, self).on_touch_move(touch)
        else:
            return super(P4, self).on_touch_move(touch)


class TestApp(App):
    list_p1 = []
    list_p2 = []
    list_p3 = []
    list_p4 = []
    drag = False
    def build(self):
        return Builder.load_string(kv)
    def point_1(self):
        print(self.root.ids)
    def point_2(self,touch):
        print(touch.pos ,  " P2")
    def point_3(self,touch):
        print(touch.pos , " P3")
    def point_4(self,touch):
        print(touch.pos , " P4")

    def get_positions(self):
        image = cv2.imread('resume_tilted.jpg')
        width, height,_ = image.shape
        print(self.root.ids.p1.position, " p1")
        print(self.root.ids.p2.position, " p2")
        print(self.root.ids.p3.position, " p3")
        print(self.root.ids.p4.position, " p4")
        p1 = self.root.ids.p1.position
        p2 = self.root.ids.p2.position
        p3 = self.root.ids.p3.position
        p4 = self.root.ids.p4.position

        p1 = [p1[0],p1[1]]
        p2 = [p2[0],p2[1]]
        p3 = [p3[0],p3[1]]
        p4 = [p4[0],p4[1]]
        for i in [p1,p2,p3,p4]:
            for j in range(2):
                i[j] = round(i[j])
        print(p1,p2,p3,p4,'---------------------------------------s')

        # resized coordinates
        '''
        It is just a matter of ratios:

        On the x-axis, you have resized by a ratio Rx = newX/oldX, and by a ratio Ry = newY/oldY on the y-axis.

        Therefore, your new coordinates for point (x,y) are (Rx * x, Ry * y)

        '''
        print(Window.size,image.shape)
        if (Window.width,Window.height)<(width,height):
            #size incriment
            x = width/Window.width
            y = height/Window.height
            pos_1 = [p1[0]*x,p1[1]*y]
            pos_2 = [p2[0]*x,p2[1]*y]
            pos_3 = [p3[0]*x,p3[1]*y]
            pos_4 = [p4[0]*x,p4[1]*y]

            for i in [pos_1,pos_2,pos_3,pos_4]:
                for j in range(2):
                    i[j] = round(i[j])

            # draw contours

            rect = cv2.rectangle(image, min([pos_1,pos_2,pos_3,pos_4]), max([pos_1,pos_2,pos_3,pos_4]), (0, 0, 0), 7)
           
            points = np.array([pos_1,pos_2,pos_3,pos_4])
            print(points  , '//////////////////////////////////')
            #points = np.array([[25,25], [70,10], [150,50], [250,250], [100,350]])
            #print(points)
            cv2.drawContours(image,[points],0,(255,0,255),7)
            image = cv2.resize(image,(800,800))
            cv2.imshow("Scanned",image)

TestApp().run()


The coordinates I am getting from kivy are not accurate and Its not working as intended . Please help me with this 
Thanks

Elliot Garbus

unread,
Sep 24, 2022, 3:59:02 PM9/24/22
to kivy-...@googlegroups.com

There are a few issues here:

class DragLabel(DragBehavior, BoxLayout , Label):

    pass

 

You are deriving DragLabel from both BoxLayout and Label.  This does not make sense.  It should be derived from a Boxlayout OR a Label.

 

class Circles():
   
pass

You are not deriving Circles from anything – but you are using the canvas attribute, this Circles should be derived from Widget.

 

The code for P1, P2, P3 and P4 is the same.  You only need one class with 4 instances.  Not 4 classes.   Make “position” a kivy property not a class attribute.

 

You mention the coordinates are not accurate.  Your issue may be that OpenCV coordinates and kivy coordinates are not the same.  Kivy coordinates put 0,0 in the bottom left, OpenCV coordinates put 0,0 in the top left.

--
You received this message because you are subscribed to the Google Groups "Kivy users support" group.
To unsubscribe from this group and stop receiving emails from it, send an email to kivy-users+...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/kivy-users/75061d44-172d-4691-a823-a4e8593b3b60n%40googlegroups.com.

 

Xero Gaming

unread,
Sep 25, 2022, 1:53:30 PM9/25/22
to kivy-...@googlegroups.com
Thanks , I figured it out too , opencv was returning width instead of height therefore the results were not desired , but now it works

Reply all
Reply to author
Forward
0 new messages