为什么kivy read_pixel没有返回预期的颜色?

2024-03-28 23:28:47 发布

您现在位置:Python中文网/ 问答频道 /正文

我正在尝试创建一个图像上的标记,允许用户选择颜色,标记特征等。最终我想有相应的图像像素,以进一步通过opencv使用。在

我有很多麻烦得到预期的颜色下触摸,它有时会返回像洋红这样的颜色,甚至在示例图像中都没有。在

我很确定问题出在如何将触摸位置转换为我要传递给read_pixel函数的值。在

我尝试过许多不同的解决方案,但都没有成功,所以我觉得我在这里缺少了一些东西。在

在主.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()

在点选择器.kv在

^{pr2}$

这是我用来测试“彩虹”的图像_棋盘.jpg““

my test image


Tags: fromposimageimportselfinitdefposition
1条回答
网友
1楼 · 发布于 2024-03-28 23:28:47

我相信这是吉普车本身的一个缺陷。特别是我认为line 901 at the kivy/core/image/__init__.py

    index = y * data.width * size + x * size
    raw = bytearray(data.data[index:index + size])
    color = [c / 255.0 for c in raw]

是错误的。应该是的

^{pr2}$

相反。在

这里重要的是,出于性能原因,内存中的位图图像在4字节地址上对齐。因此有一个显式的data.rowlength字段。通常这一行工作得很好,因为图像通常是对齐的,这样data.rowlength = data.width * size。但是您的特定图像是不同的:它使用3字节RGB格式(没有alpha),它的宽度是奇数561,即data.width * size=1683,因此data.rowlength应该向上取整为1684,实际上是这样,但是代码没有考虑到这一点。这意味着你经常从两个连续的像素和随机旋转的RGB组件读取颜色。在

另外,由于您的图像使用JPEG格式,所以“单元格”之间的边界并不严格。若您非常努力地放大,您可以从左下角看到一些压缩伪影。在

JPEG Artifacts

那些被前面提到的随机颜色分量旋转错误所掩盖的伪影给了你非常奇怪(似乎不存在)的颜色。在

可能的解决办法

  1. 更改图像,使其在内存中预先对齐,并且错误不会影响您(例如,使用mutliple of 4作为宽度)
  2. 或者等待一个错误被修复
  3. 在本地修补kivy/core/image/__init__.py文件(我试过了,它似乎工作得很好)。在

相关问题 更多 >