简体   繁体   English

如何尽快将像素与其周围环境进行比较?

[英]How to compare a pixel with its surounding as fast as possible?

I am trying to find a fast algorithm such as :我正在尝试找到一种快速算法,例如:

  • input: Image (width wx height h) , radius R输入: Image (width wx height h)radius R

  • content: for each pixel (x,y) as内容:对于每个像素 (x,y) 作为

    • x in [R, wR] [R, wR] 中的 x
    • y in [R, hR] y 在 [R, hR]

    find the most represented color in the circle of radius R and center (x,y).在半径为R和中心 (x,y) 的圆中找到最具代表性的颜色。 (In the image) (在图像中)

  • output: Image (w-2R x h-2R) the image built from the results输出: Image (w-2R x h-2R)根据结果​​构建的图像

I have, for now, implemented the base algorithm of that in python, that has a complexity O(n*R^2) (with n = w*h ).目前,我已经在 python 中实现了基本算法,它的复杂度为O(n*R^2)n = w*h )。

I'm now wondering if an algorithm of complexity O(n) may exist.我现在想知道是否可能存在复杂度为O(n)的算法。 It sounds possible to me, but I cannot manage to build one.对我来说这听起来可能,但我无法建立一个。

So:所以:

  • Do you think a such algorithm may exist ?你认为可能存在这样的算法吗?
    • If so, what would he use / how would he work ?如果是这样,他将使用什么/他将如何工作?
    • Otherwise, why ?否则,为什么?
  • How can I speed up the execution of my algorithm ?如何加快算法的执行速度? (in an algorithm way, ie regardless of parallelization) (以算法方式,即与并行化无关)

Edits :编辑

  • I use an image representation with a 2 dimensions array.我使用带有二维数组的图像表示。 Each pixel (ie cell of the array) is a tuple of ints: Red, Green, Blue, between 0 and 255.每个像素(即阵列的单元格)是一个整数元组:红、绿、蓝,介于 0 和 255 之间。
  • Before running this algorithm, I "level" the image: reduce the number of different colors present in the image (by a kind of clustering on color and proximity)在运行这个算法之前,我对图像进行“调平”:减少图像中不同颜色的数量(通过一种颜色和接近度的聚类
  • If every pixel is different in the surrounding, then it should remain with the same color (for now implemented by giving a "weight" more important to the original pixel's color)如果周围的每个像素都不同,那么它应该保持相同的颜色(现在通过赋予原始像素颜色更重要的“权重”来实现)

Note: I am not sure that "comparing a pixel with its surrounding" is the best way to describe what I want to do, so if you have ideas to improve the title, let me know in the comments注意:我不确定“将像素与其周围的像素进行比较”是描述我想要做什么的最佳方式,因此如果您有改进标题的想法,请在评论中告诉我

Based on Cris Luengo comments, I improved my algorithm by:根据Cris Luengo 的评论,我通过以下方式改进了我的算法:

  • Replacing data structure's content from tuples of int to ids of clusters将数据结构的内容从 int 元组替换为集群 ID
  • Using a "moving kernel": from pixel (x,y) to (x+1, y), only updating the content about the cells leaving and entering the kernel使用“移动内核”:从像素 (x,y) 到 (x+1, y),仅更新有关离开和进入内核的单元格的内容
    • This improvement is more visible as the radius R grows随着半径R增加,这种改进更加明显

So, input: image , radius所以,输入: imageradius

  1. Replace colors by ids用 id 替换颜色

    colors = {} id_counter = 0 raw = np.zeros((image.width, image.height)) data = image.load() for x in range(image.width): for y in range(image.height): color = data[x,y] id = colors.get(color, -1) if id == -1: id = id_counter id_counter += 1 colors[color] = id raw[x,y] = id
  2. Build kernel and delta kernel .构建kerneldelta kernel Delta kernel contains the relative positions of cells leaving and entering, and if they are leaving or entering Delta 核包含细胞离开和进入的相对位置,以及它们是离开还是进入

    kernel = [] for dx in range(-radius, radius+1): for dy in range(-radius, radius+1): if dx*dx + dy*dy <= radius*radius: kernel.append((dx,dy)) delta_kernel = [] for dx in range(-radius, radius+1): mini = None for dy in range(-radius, radius+1): if dx*dx + dy*dy <= radius*radius: mini = dy - 1 break delta_kernel.append((dx, mini, -1)) for dx in range(-radius, radius+1): maxi = -9999 for dy in range(-radius, radius+1): if dx*dx + dy*dy <= radius*radius: maxi = max(dy, maxi) delta_kernel .append((dx, maxi, 1))

    Note: this is actually merged in one loop, but for sake of clarity, I separated the steps注意:这实际上合并在一个循环中,但为了清楚起见,我将步骤分开

  3. Actual algorithm实际算法

    counter = {} # Map counting occurrences new_raw = np.zeros((raw.shape[0] - radius*2, raw.shape[1] - radius*2)) direction = +1 # Y direction +/-1 y = radius for x in range(radius, raw.shape[0]-radius): if x == radius: # First time: full kernel for (dx, dy) in kernel: key = raw[x+dx, y+dy] counter[key] = counter.get(key, 0) + 1 else: # move to the right (x++): delta kernel horizontally for (dy, dx, sign) in delta_kernel: key = raw[x + dx, y + direction*dy] new_val = counter.get(key,0) + sign if new_val <= 0: counter.pop(key) # Remove key to useless key values in the map else: counter[key] = new_val for i in range(raw.shape[1]-2*radius): if i > 0: # y moves forward: delta radius (on y=0, x moved forward not y) for (dx, dy, sign) in delta_kernel: key = raw[x + dx, y + direction*dy] new_val = counter.get(key,0) + sign if new_val <= 0: counter.pop(key) else: counter[key] = new_val # Find most represented value winner_item = max(counter.items(), key=lambda i:i[1]) if winner_item[1] == 1: # Every pixels are different: take the center one by default. winner_key = raw[x,y] else: winner_key = winner_item[0] new_raw[x-radius, y-radius] = winner_key y += direction y -= direction # Prevent y to go out from range direction *= -1
  4. Rebuild an image重建镜像

    reversed_color_map = {} for key, value in colors.items(): reversed_color_map[value] = key result = Image.new(mode=image.mode, size=(image.width-2*radius, image.height-2*radius)) out_data = result.load() for x in range(raw.shape[0]): for y in range(raw.shape[1]): out_data[x,y] = reversed_color_map[raw[x,y]]

Comments, remarks, ideas for improvement are welcome :)欢迎评论,评论,改进想法:)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM