У меня есть png, который я превратил в pd.DataFrame, который содержит логические значения. Для белого пикселя я получаю «False», а для черного пикселя «True». Я хотел бы создать диаграмму DXF. Для этого я пытаюсь получить координаты для каждого «True» на фрейме данных, чтобы потом я мог соединить их, чтобы нарисовать линию.

Это код, который у меня сейчас есть:

from PIL import Image
import numpy as np
import pandas as pd

img = Image.open('/home/sinushas/Downloads/Brezynio_Konvertavimas/test.png')
thresh = 200
fn = lambda x : 255 if x > thresh else 0
r = img.convert('L').point(fn, mode='1')
r.save('/home/sinushas/Downloads/Brezynio_Konvertavimas/test_converted.png')

im = Image.open('/home/sinushas/Downloads/Brezynio_Konvertavimas/test_converted.png')
im2arr = np.array(im) # im2arr.shape: height x width x channel

df = pd.DataFrame(im2arr)
df = (df == False) 

Это сгенерированный pd.Dataframe:

    0   1   2   3   4   5   6   7   8   9
0   False   False   False   False   False   False   False   False   False   False
1   False   False   False   False   False   False   False   False   False   False
2   False   False   True    True    True    True    True    True    False   False
3   False   False   False   False   True    True    False   False   False   False
4   False   False   False   False   True    True    False   False   False   False
5   False   False   False   False   True    True    False   False   False   False
6   False   False   False   False   True    True    False   False   False   False
7   False   False   False   False   False   False   False   False   False   False
8   False   False   False   False   False   False   False   False   False   False
9   False   False   False   False   False   False   False   False   False   False

Я ожидаю получить следующие координаты: (2: 3), (2: 4), (2: 5), (2: 6), (2: 7), (2: 8), (3: 5), ( 3 : 6 ) , ( 4 : 5 ) , ( 4 : 6 ) , ( 5 : 5 ) , ( 6: 6 ) , ( 6 : 5 ) , ( 6: 6 )

Я не нашел работающий кусок кода, который мог бы получить мне какие-либо координаты из Dataframe .. Что я пробовал:

result = im2arr.where('True')

df.sort_index() 

res = [i for i, val in enumerate(df) if val]

Спасибо за любые советы.

2
Dong Long Wang 20 Окт 2019 в 18:00

4 ответа

Используйте np.where:

coord = np.where(df)

coordinates = [(x,y) for x, y in zip(coord[0], coord[1])]

Вывод

[(2, 2),
 (2, 3),
 (2, 4),
 (2, 5),
 (2, 6),
 (2, 7),
 (3, 4),
 (3, 5),
 (4, 4),
 (4, 5),
 (5, 4),
 (5, 5),
 (6, 4),
 (6, 5)]
1
Erfan 20 Окт 2019 в 18:16

np.nonzero:

[(x,y) for x,y in zip(*np.nonzero(df.values))]

Выход:

[(2, 2),
 (2, 3),
 (2, 4),
 (2, 5),
 (2, 6),
 (2, 7),
 (3, 4),
 (3, 5),
 (4, 4),
 (4, 5),
 (5, 4),
 (5, 5),
 (6, 4),
 (6, 5)]

​
0
Quang Hoang 20 Окт 2019 в 18:18

DataFrame.stack

Чтобы выполнить логическое индексирование.

df2=df.stack()
coordinates=[*df2[df2].index]

#print(coordinates)
[(2, 2),
 (2, 3),
 (2, 4),
 (2, 5),
 (2, 6),
 (2, 7),
 (3, 4),
 (3, 5),
 (4, 4),
 (4, 5),
 (5, 4),
 (5, 5),
 (6, 4),
 (6, 5)]
0
Community 20 Июн 2020 в 12:12

Вам не нужно pandas для этого. И вам не нужно читать это снова. Вы даже можете использовать L в .point(fn, mode='L')

r = img.convert('L').point(fn, mode='1')
r.save(...)

data = np.where(r)          # [[y1,y2,...], [x1,x2,...], ]
points = list(zip(*data))   # [[y1,x1], [y2,x2], ...]

print(points)

Вы можете напрямую использовать where() в r, чтобы получить список с [[y1,y2,...], [x1,x2,...]].

И затем вы можете использовать zip() для создания пар [y1, x1], [y2,x2] и т. Д.

РЕДАКТИРОВАТЬ: . Для других пикселей вы можете использовать ~ для отмены значений в r

data = np.where(~r)          # other pixels

Массив работает с координатами (row, columns), что означает (y, x) - как в ожидаемых вами данных (2,3), (2,4) - но если вам понадобится (x, y), тогда используйте:

points = list(zip(data[1], data[0]))

В итоге

points = [(x,y) for y,x in zip(*data)]

РЕДАКТИРОВАТЬ: вам даже не нужно .point()

from PIL import Image
import numpy as np

img = Image.open('image.png').convert('L')

arr = np.array(img)

#data = np.where( arr > 200 )    # for white pixels
#data = np.where( ~(arr > 200) ) # for black pixels too
data = np.where(arr < 200) # for black pixels

points_y_x = list(zip(*data))
points_x_y = list(zip(data[1], data[0]))

print(points_y_x)
print(points_x_y)
0
furas 20 Окт 2019 в 20:38
Если я использую ваш код из редактирования, он, кажется, дает мне все кординаты из изображения, которое окрашено в белый цвет, а не в черный
 – 
Dong Long Wang
20 Окт 2019 в 19:40
Когда я тестировал ваш код, он дает True для белых пикселей, поэтому мой код также дает координаты для тех же элементов. Но вы можете использовать < 200 вместо > 200, чтобы получить черный вместо белого.
 – 
furas
20 Окт 2019 в 20:21
В первой версии вы можете использовать ~ для отрицания значений - data = np.where(~r)
 – 
furas
20 Окт 2019 в 20:28
Я вижу проблему. Я не использовал DataFrame и пропустил вашу последнюю строку df = (df == False), которая отрицает значения в DataFrame. Так что вы должны использовать ~r в моем коде, чтобы придавать значения значениям. Во втором примере используйте ~(arr > 200) вместо arr > 200 или просто arr < 200
 – 
furas
20 Окт 2019 в 20:36
Спасибо, что объяснили, я попробую!
 – 
Dong Long Wang
20 Окт 2019 в 22:11