Попытка сделать наивный numpy код обработки изображений быстрее - PullRequest
0 голосов
/ 18 апреля 2020

Я пытаюсь преобразовать изображение, содержащее цветные символы, в пиксельную графику, как показано справа (см. Изображение ниже), где каждый цветной символ (занимающий несколько пикселей) будет заменен на один пиксель цвета символа.

Пример того, чего я пытаюсь достичь

До сих пор я написал довольно наивный алгоритм, который просто перебирает все пиксели и довольно медленный sh. Я считаю, что мог бы сделать это быстрее, например, используя собственные операции numpy, но я не смог найти как. Любые советы?

(Я также начал с попытки просто изменить размер изображения, но не смог найти алгоритм повторной выборки, который бы позволил ему работать).

def resize(img, new_width):
    width, height = img.shape[:2]
    new_height = height*new_width//width
    new_image = np.zeros((new_width, new_height,4), dtype=np.uint8)
    x_ratio, y_ratio = width//new_width, height//new_height
    for i in range(new_height):
        for j in range(new_width):
            sub_image = img[i*y_ratio:(i+1)*y_ratio, j*x_ratio:(j+1)*x_ratio]
            found = False
            for row in sub_image:
                for pixel in row:
                    if any(pixel!=[0,0,0,0]):
                        new_image[i,j]=pixel
                        break
                if found:
                    break
    return new_image

Больше пример

Ответы [ 2 ]

1 голос
/ 18 апреля 2020
import cv2
import numpy as np

img=cv2.imread('zjZA8.png')
h,w,c=img.shape
new_img=np.zeros((h//7,w//7,c), dtype='uint8')

for k in range(c):
    for i in range(h//7):
        for j in range(w//7):
            new_img[i,j,k]=np.max(img[7*i:7*i+7,7*j:7*j+7,k])
cv2.imwrite('out3.png', new_img)

enter image description here Слева - результат с np.mean, в центре - исходное изображение, справа - результат с np.max

Пожалуйста, проверьте этот код:

img=cv2.imread('zjZA8.png')
h,w,c=img.shape
bgr=[0,0,0]
bgr[0], bgr[1],bgr[2] =cv2.split(img)
for k in range(3):
    bgr[k].shape=(h*w//7, 7)
    bgr[k]=np.mean(bgr[k], axis=1)
    bgr[k].shape=(h//7, 7, w//7)
    bgr[k]=np.mean(bgr[k], axis=1)
    bgr[k].shape=(h//7,w//7)
    bgr[k]=np.uint8(bgr[k])
out=cv2.merge((bgr[0], bgr[1],bgr[2]))
cv2.imshow('mean_image', out)
0 голосов
/ 18 апреля 2020

Модификация моего кода для использования нативной операции np.nonzero сделала свое дело! Я снизился с ~ 8 с до ~ 0,32 с на изображении 1645x1645 (с new_width = 235). Я также попытался использовать numba, но накладные расходы замедлились.

def resize(img, new_width):
    height, width = img.shape[:2]
    new_height = height*new_width//width
    new_image = np.ones((new_height, new_width,3), dtype=np.uint8)
    x_ratio, y_ratio = width//new_width, height//new_height
    for i in range(new_height):
        for j in range(new_width):
            sub_image = img[i*y_ratio:(i+1)*y_ratio, j*x_ratio:(j+1)*x_ratio]
            non_zero = np.nonzero(sub_image)
            if non_zero[0].size>0:
                new_image[i, j]=sub_image[non_zero[0][0],non_zero[1][0]][:3]
    return new_image

...