Цикл по пикселям с Cython все еще медленный - PullRequest
0 голосов
/ 11 декабря 2018

Я не получаю никакой разницы в скорости между обычным кодом Python.В нем говорится, что узким местом являются последние две строки кода в html-файле.Есть ли способ обойти это?

Что я пытаюсь сделать, это перебрать пиксели и добавить координаты, где значение rgb ниже 210 к списку.

from PIL import Image
import numpy as np
import time
import cython
import cv2

filename = "/home/user/PycharmProjects/Testing/files/file001.png"
image = Image.open(filename)
size = width, height = image.size
image_data = np.asarray(image)

cdef list list_text = []

@cython.boundscheck(False)
cpdef get_image_data():
    cdef int y, x
    for y in range(1683):
        for x in range(1240):
            if image_data[y, x] < 210:
                list_text.append([x, y])

Ответы [ 3 ]

0 голосов
/ 12 декабря 2018

Я бы предложил использовать функцию Numpy argwhere() следующим образом:

import numpy as np

# Create a starting image
im = np.arange(0,255,16).reshape(4,4)                                                      

Это выглядит так:

array([[  0,  16,  32,  48],
       [ 64,  80,  96, 112],
       [128, 144, 160, 176],
       [192, 208, 224, 240]])

Теперь найдите координаты всех элементов меньше 210:

np.argwhere(im<210)  

Это выглядит так:

array([[0, 0],
       [0, 1],
       [0, 2],
       [0, 3],
       [1, 0],
       [1, 1],
       [1, 2],
       [1, 3],
       [2, 0],
       [2, 1],
       [2, 2],
       [2, 3],
       [3, 0],
       [3, 1]])
0 голосов
/ 19 декабря 2018

Зацикливание не является проблемой, но добавление списков в списки происходит очень медленно.Чтобы избежать этого, вы можете либо выделить массив, достаточно большой для данных, и затем уменьшить его (или скопировать данные в массив, который имеет нужный вам размер), или вы можете реализовать свою функцию, используя std:vector.

* 1003.* В этом ответе я использую Numba, потому что я не настолько опытен в программировании на языке Cython, но реализация Cython должна быть прямой.Numba также имеет ограниченное внутреннее представление списка и кортежей, но я не знаю, доступно ли это в Cython.

Пример

import numpy as np
import numba as nb

@nb.njit()
def get_image_data_arr(image_data):
  array_text = np.empty((image_data.shape[0]*image_data.shape[1],2),dtype=np.int64)
  ii=0
  for y in range(image_data.shape[0]):
    for x in range(image_data.shape[1]):
      if image_data[y, x] < 210:
        array_text[ii,0]=x
        array_text[ii,1]=y
        ii+=1
  return array_text[:ii,:]

@nb.njit()
def get_image_data(image_data):
  list_text = []
  for y in range(image_data.shape[0]):
    for x in range(image_data.shape[1]):
      if image_data[y, x] < 210:
         #appending lists
         list_text.append([x, y])
         #appending tuples
         #list_text.append((x, y))
  return list_text

Timings

Все тайминги не содержат служебных данных компиляции (первый вызов функции исключен из таймингов).

#Create some data
image_data=np.random.rand(1683*1240).reshape(1683,1240)*255
image_data=image_data.astype(np.uint8)


get_image_data (Pure Python)                   : 3.4s
get_image_data (naive Numba, appending lists)  : 1.1s
get_image_data (naive Numba, appending tuples) : 0.3s
get_image_data_arr:                            : 0.012s
np.argwhere(image_data<210)                    : 0.035s
0 голосов
/ 11 декабря 2018

Хорошо, так что я вроде как это исправил.Теперь я должен выяснить, как сохранить эти координаты пикселей в двумерном массиве.Поскольку, если я добавлю стиль Python, это замедлит все это.Какие-либо предложения?Я также не очень хочу возвращать image_data снова.

Кстати, этот код в 28000 раз быстрее, чем Python!Я ожидал увеличения скорости в 100 раз, не так уж много.

@cython.boundscheck(False)
cpdef const unsigned char[:, :] get_image_data(const unsigned char[:, :] image_data):

cdef int x, y
cdef list list_text = []

for y in range(1683):
    for x in range(1240):
        if image_data[y, x] < 210:
            pass
return image_data
...