Сжатие бинарного массива в 4 раза
Есть бинарный массив α (из 0 и 1) размером AxA.
Хочу получить новый бинарный массив β размером BxB.
B в 2 раза меньше A, следовательно массив BxB в 4 раза меньше, чем AxA.
Правило следующее:
- "Пиксель"
(x;y)массива β равен единице, если единице равен хотя бы один из следующих элементов массива α:(2x; 2y), (2x+1; 2y), (2x; 2y+1), (2x+1; 2y+1)
Имею такой код:
def compress_4_times (canvas):
new_size = 16
field = [[0]*new_size]*new_size
for y in range(0, new_size):
for x in range(0, new_size):
_x, _y = 2*x, 2*y
count_active = 0
if is_pixel_active(canvas, _x, _y):
count_active += 1
if is_pixel_active(canvas, _x+1, _y):
count_active += 1
if is_pixel_active(canvas, _x, _y+1):
count_active += 1
if is_pixel_active(canvas, _x+1, _y+1):
count_active += 1
if count_active > 0:
field[x][y] = True
else:
field[x][y] = False
return field
На вход подается массив α, возвращаться должен β. В данном примере размер α - 32.
Проблема:
По ходу выполнения цикла все работает нормально, я проверял принтами: некоторые пиксели становятся True, и судя по всему даже правильные.
Но функция возвращает массив с одними False! В ней нет ни одного True!
Такое ощущение, что после завершения цикла, field почему-то сбрасывается. Почему такое может быть?
Надеюсь, я правильно вывел правило перевода. Например, я хочу превратить такое:
0 0 0 1
0 1 1 0
0 0 0 1
0 0 1 1
в такое:
1 1
0 1
Ответы (2 шт):
Эта проблема уже много раз обсуждалась тут, нужно только уметь её распознать. Замените инициализацию списка списков на такую:
field = [[0] * new_size for _ in range(new_size)]
Проблема вашей инициализации в том, что второе умножение там не создаёт новые списки, а клонирует ссылку на один и тот же список много раз. Из-за этого любые изменения в одном из списков тут же отражаются во всех остальных списках - ведь это один и тот же список.
А вот с первым умножением проблем нет, потому что 0 - это скаляр и при его "размножении" создаётся нормальный список из значений, а не из ссылок.
Проверки ваши, кстати, можно сильно сократить (и ускорить - проверки будут выполняться не все, а до первой успешной):
field[x][y] = any((
is_pixel_active(canvas, _x, _y),
is_pixel_active(canvas, _x+1, _y),
is_pixel_active(canvas, _x, _y+1),
is_pixel_active(canvas, _x+1, _y+1)
))
А вообще операция, которую вы делаете, называется pooling, есть такой штатный слой в нейросетях, в частности в библиотеке Keras.
можно еще попробовать такой способ сжатия:
matr = [[0,0,0,1,0,0],
[1,0,0,1,0,1],
[0,0,1,1,0,0],
[0,0,1,0,0,0],
[0,0,0,1,0,1],
[0,0,0,1,0,0]
]
matr2=[]
for i in range(0,len(matr),2):
m = [x or y for x,y in zip(*matr[i:i+2])]
matr2.append([x or y for x,y in zip(m[::2],m[1::2])])
print(matr2)
результат:
[[1, 1, 1],
[0, 1, 0],
[0, 1, 1]]
UPD
для других степеней сжатия придется этот код частично переписать. Например для сжатия в 9 раз получится так:
matr = [[0,0,0,1,0,0],
[1,0,0,1,0,1],
[0,0,1,1,0,0],
[0,0,0,0,0,0],
[0,0,0,1,0,1],
[0,0,0,1,0,0]
]
matr2=[]
for i in range(0,len(matr),3):
m = [x or y or z for x,y,z in zip(*matr[i:i+3])]
matr2.append([x or y or z for x,y,z in zip(m[::3],m[1::3],m[2::3])])
print(matr2)
результат:
[[1, 1],
[0, 1]]