1

Using OpenCV, I am trying to pass a jpg picture into a numpy array, change some of the pixels and export the changed jpg image with cv2.imwrite and then decode it. This looks like it works as the image file was originally 463kb and after the new file is written the file size is 866kb.

The problem is that the decoder program returns gibberish. I'm not sure how to proceed. Any help would be appreciated.

Example Output::

Code or Decode
decode
What is the location of the Image?
Example format> C:\Users\username\folder\filename.jpg
C:\\Users\\ph1\\Desktop\\coding\\message.jpg
.~>;989;<<=:8;88;>==>@@?>8;;;::998:9;<;;?>=>>@A??<????????>??>>?@>??>>>>?@<>??>??B=?BBABC>@@?@@?AB>?AA?==??@@???@@@@?ACAAB@BBA?>?D>>@>;?HXG954465635*,HãÔÐȾ¼¾º´¼¼¹¹½¿À½½¿ÁÂÁÀ¿ÄÆÄÂÅÅÁ¿»ÂÀ»¾ÅÄÂÆÄÃÃÃÃÃþ½»¾Â¿¹·½Ê¼¼®F


Code
-----------------
import cv2
#changing message chars to ordinals
def stego_generator(message):
    for char in message:
        yield ord(char)
        
#read image into numpy arrray function with cv2
def get_img(img_loc):
    img = cv2.imread(img_loc)
    return img
#getting greated common denomenator to change pixels
def gcd(x,y):
    while(y):
        x, y = y, x % y
    return x

#steganography encoder function
def encode_stego(img_loc, msg):
    img = get_img(img_loc)
    msg_gen = stego_generator(msg)
    pattern = gcd(len(img), len(img[0]))
    for i in range(len(img)):
        for j in range(len(img[0])):
            if (i+1 * j+1) % pattern == 0:
                try:
                    img[i-1][j-1][0] = next(msg_gen)
                except StopIteration:
                    img[i-1][j-1][0] = 0
                    return img
                
#steganography decoder function
def decode_stego(img_loc):
    img = get_img(img_loc)
    pattern = gcd(len(img), len(img[0]))
    message = ''
    for i in range(len(img)):
        for j in range(len(img[0])):
            if (i-1 * j-1) % pattern == 0:
                if img[i-1][j-1][0] != 0:
                    message = message + chr(img[i-1][j-1][0])
                else:
                    return message

print('For PC')
choice = input('Code or Decode\n')
print('What is the location of the Image?')
file_loc = input('Example format> C:\\Users\\username\\folder\\filename.jpg\n')
if choice.lower() == 'code':
    to_code = input('What is your message?\n')
    secret_message = to_code
    encoded_img = encode_stego(file_loc, secret_message)
    file_name = input('What would you like to call the Image File?\n')
    cv2.imwrite(file_name, encoded_img)
elif choice.lower() == 'decode':
    print(decode_stego(file_loc))
else:
    print('Command not available')```

ph1-618o
  • 21
  • 2
  • 1
    Jpeg is a lossy format. Use bmp/png instead. – Reti43 Mar 18 '21 at 21:30
  • thanks! I'll give that a try – ph1-618o Mar 19 '21 at 11:50
  • That worked!! Thank you so much! I'll just have to look into how to circumvent the lossieness of jpeg compression for the furture. I also noticed that if it was originally a jpeg and then converted by a photo program to png, it also caused an error. – ph1-618o Mar 19 '21 at 16:45
  • Jpeg steganography requires a different approach. You can read [here](https://stackoverflow.com/questions/29677726/steganography-in-lossy-compression-java) and [here](https://stackoverflow.com/questions/35396977/lsb-dct-based-image-steganography) to get an idea. You can use a jpeg image as your cover medium, because you read it as an array of pixels. But after embedding your secret you have to save it to a lossless format. If you save it to jpeg and then resave that to png, your secret won't magically come back. It's been forever destroyed. – Reti43 Mar 19 '21 at 21:07

0 Answers0