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"
