遍历阈值区域不会改变像素值

Looping over the threshold area does not change pixel values

我目前正在设计隐写术系统,该系统使用 Python 和 OpenCV 库使用多种技术(K-means、Canny 边缘检测)检测图像中的特定区域。 我在更新图像像素值以在最低有效位中包含我的秘密数据时遇到了一个大问题。

经过几次计算,我开始寻找阈值。

thresh = cv.adaptiveThreshold(imgray,100,cv.ADAPTIVE_THRESH_GAUSSIAN_C, cv.THRESH_BINARY_INV,11,2)

为了测试该区域,我执行了以下操作:

Testim=np.copy(originalImage) 
Testim[thresh==0]=[0,255,0]
plt.imshow(Testim)
plt.show()

它显示了这张图片,指示我要循环的区域:

Image showing after the threshold Isolation in green

之后,我进行了一个循环,我将向您展示它的一个片段,它遍历 RGB 值并用秘密数据中的一些位更改每个最低有效位。我想指出原始图像形状是 (1024,1024,3) 并且图像 [thresh==0] 的形状是 (863843, 3) :

 for i in range(image[thresh==0].shape[0]): 
      # convert RGB values to binary format
      r, g, b = to_bin(image[thresh==0][i])
              # modify the least significant bit only if there is still data to store
      if data_index < data_len:
              # least significant red pixel bit
        image[thresh==0][i][0] =int (r[:-1] + binary_secret_data[data_index], 2)
        data_index += 1 
      if data_index < data_len:
              # least significant green pixel bit
        image[thresh==0][i][1] = int (g[:-1] + binary_secret_data[data_index], 2)
        data_index += 1
      if data_index < data_len:
              # least significant blue pixel bit
        image[thresh==0][i][2] = int (b[:-1] + binary_secret_data[data_index], 2)
        data_index += 1
                # if data is encoded, just break out of the loop
      if data_index >= data_len:
        plt.imshow(image)
        break
    return image,thresh

问题是RGB的值在循环内外根本没有变化,我加了一些print语句,一直显示0,我也试过显式赋值1,但是没有要么工作。

我要注意,这只是编码功能的一部分

非常感谢你的帮助

您的问题是高级索引 returns 数组副本,因此通过一直执行 image[thresh==0][i][j] 修改新创建的副本,然后将其丢弃。

让我们从一些假数据开始

import cv2
import numpy as np

np.random.seed(0)

original = np.random.randint(0, 255, (1024, 1024, 3)).astype(np.uint8)
gray = cv2.cvtColor(original, cv2.COLOR_RGB2GRAY)
thresh = cv2.adaptiveThreshold(gray, 100, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY_INV, 11, 2)
copy = np.copy(original)
copy[thresh==0] = [0, 255, 0]

现在看看会发生什么

>>> copy[thresh==0][0]
array([  0, 255,   0], dtype=uint8)
>>> copy[thresh==0][0] = [1, 2, 3]
>>> copy[thresh==0][0]
array([  0, 255,   0], dtype=uint8)

为了使结果保持一致,您应该使用 numpy.where 获取阈值为 0 的单个索引。

idx = np.where(thresh==0)
for row, col in zip(*idx):
    r, g, b = to_bin(copy[row,col])
    copy[row,col,0] = modified_red_pixel
    # etc

我个人会建议以下内容,这样您就可以避免 python 循环和不断检查以查看您是否还有要嵌入的数据。

binary_secret_data = '01010000101010010101010001001100'
binary_secret_data = np.array(list(map(int, binary_secret_data)))
secret_len = len(binary_secret_data)

# The result is a tuple of (array of all row coords, array of all column coords)
idx = np.where(thresh==0)
# Make 3 copies of each pixel coordinate and add 0, 1, 2 repeatedly for the RGB of each pixel
idx = (np.repeat(idx[0], 3), np.repeat(idx[1], 3), np.array([0, 1, 2] * len(idx[0])))
# Only keep as many pixels as data you have to embed
idx = (idx[0][:secret_len], idx[1][:secret_len], idx[2][:secret_len])

# Boom, power of vectorisation
copy[idx] = copy[idx] & 0xfe | binary_secret_data

现在可以看到前32个像素已经修改成功

>>> copy[thresh==0][:15]
array([[  0, 255,   0],
       [  1, 254,   0],
       [  0, 254,   1],
       [  0, 255,   0],
       [  1, 254,   0],
       [  1, 254,   1],
       [  0, 255,   0],
       [  1, 254,   0],
       [  0, 255,   0],
       [  0, 255,   1],
       [  0, 254,   0],
       [  0, 255,   0],
       [  0, 255,   0],
       [  0, 255,   0],
       [  0, 255,   0]], dtype=uint8)