Why is kivy read_pixel not returning expected color?

Viewed 828

I am trying to create markers on an image that would allow a user to select colors, mark features etc. Ultimately I would like to have the corresponding image pixel for further use via opencv.

I'm having a lot of trouble getting the expected color under the touch and it sometimes returns colors like magenta which are not even in the example image.

I am pretty sure the problem is with how I am converting the touch position to the values I am handing to the read_pixel function.

I have tried many different solutions without success so I think there is something I am missing here.

main.py

from kivy.app import App
from kivy.properties import ListProperty, ObjectProperty
from kivy.uix.image import AsyncImage
from kivy.uix.relativelayout import RelativeLayout
from kivy.uix.widget import Widget
from kivy.uix.screenmanager import ScreenManager, Screen


class Marker(Widget):
    selected_color = ListProperty([0,1,0])

    def __init__(self, **kwargs):
        super(Marker, self).__init__(**kwargs)
        self.selected_pos = None

    def on_touch_down(self, touch):
        if self.collide_point(*touch.pos):
            print("Touched at Marker: {0}".format(touch.spos))

    def on_touch_move(self, touch):
        self.set_position_from_touch(touch.spos)

    def set_position_from_touch(self, spos):
        # print("touch: {0}".format(touch))
        self.image = self.parent.parent.image
        x = spos[0] * self.image.width
        y = spos[1] * self.image.height

        # setting position of the widget relative to touch
        self.pos = (x-self.width/2, y-self.height*(2/3))
        # self.pos = (x, y)

        print("widget position : {0}".format(self.pos))
        # converting widget position to pixel(row, column of
        selected_pixel = self.image.to_row_col(self.pos)
        print("selected Pixel: {0}".format(selected_pixel))

        try:
            self.selected_color = self.image._coreimage.read_pixel(
                selected_pixel[0],
                selected_pixel[1])
                # this skips conversion and just uses pos
                # self.pos[0],
                # self.pos[1])
        except IndexError:
            print("position out of range")


class MarkerManager(RelativeLayout):
    def __init__(self, **kwargs):
        super(MarkerManager, self).__init__(**kwargs)
        self.marker_mode = None
        self.features = []

    def on_touch_down(self, touch):
        if self.collide_point(*touch.pos):
            child_touched = False
            print("Touched: {0}".format(touch))
            if self.children:
                for child in self.children[:]:
                    if child.collide_point(touch.pos[0], touch.pos[1]):
                        child_touched = True
                        child.dispatch('on_touch_down', touch)
            if not child_touched:
                print("Touched only Image at: {0}".format(touch.spos))
                marker = Marker()
                self.features.append(marker)
                self.add_widget(marker)
                marker.set_position_from_touch(touch.spos)

class SelectedImage(AsyncImage):
    def __init__(self, **kwargs):
        super(SelectedImage, self).__init__(**kwargs)
        self.allow_stretch=True
        self.keep_ratio=False

    def to_row_col(self, pos):
        pixels_x = self._coreimage.width
        pixels_y = self._coreimage.height
        pixel_x = (pos[0] / self.width) * pixels_x
        # pixel_y = (pos[1] / self.height) * self.pixels_y
        pixel_y = (1 - (pos[1] / self.height)) * pixels_y
        # should correspond to row column of image
        return [int(pixel_x), int(pixel_y)]

class ImageScreen(Screen):
    image = ObjectProperty()
    manager = ObjectProperty()
    def __init__(self, **kwargs):
        super(ImageScreen, self).__init__(**kwargs)

class PointsSelectorApp(App):
    def build(self):
        return ImageScreen()

if __name__ == "__main__":
    PointsSelectorApp().run()

pointsselector.kv

<ImageScreen>:
    image: image_id
    manager: manager_id

    SelectedImage:
        id: image_id
        source: "rainbow_checkerboard.jpg"
        keep_data: True

    MarkerManager:
        id: manager_id


<Marker>:
    size_hint: None, None
    size: "40dp", "40dp"
    canvas:
        Color:
            rgb: self.selected_color
        Ellipse:
            pos: self.pos[0]+self.width/4, self.pos[1]+self.height/3
#            pos: self.pos[0], self.pos[1]
            size: self.width*.6, self.height*.6

here is my image i have been using to test with "rainbow_checkerboard.jpg"

my test image

1 Answers
Related