n度あることはn+1度ある

憶測が多いブログなので鵜呑みにしないこと

OpenCVでステガノグラフィの実験をしてみる

今までだ・である調を使ってブログを書いてきたが、普通に書きにくいので以下よりです・ます調でブログを書いていく。
以上蛇足

OpenCVを使って、画像に画像を埋め込むステガノグラフィ的なことをしてみました。

埋め込み対象画像

hidden.bmp f:id:benntann:20180714014405j:plain

埋め込む画像

hide.bmp f:id:benntann:20180714014441j:plain

ステグした画像

output.bmp f:id:benntann:20180714014707j:plain

ぱっと見はそこまで変わりませんが、ステグした画像の背景をよく見ると、「ステ」の文字が薄っすらと見えます。記載している復号用のプログラムを使用すれば、hide.bmpが取り出せます。
アルゴリズムとしては、埋め込む画像の1つの画素のRGB情報を、2bitずつにして埋め込み先の画像の下位2bitに設定して実現しています。つまり1つの画素情報を4つの画素に分けて保存しています。こんな単純なアルゴリズムでも、殆ど変わりがないレベルなので、実際に使用されているアルゴリズムで作られた画像は、バイナリエディタなどで数値的に観ない限りわからないレベルなのでしょうか。
猫の画像はフリー画像です。

以下ソースコード
※埋め込みは400*100 -> 400*400、取り出しは400*100 <- 400*400のみ対応

steg.cc

#include "opencv2/highgui.hpp"
int main(){
  cv::Mat hidden,hide;
  cv::Vec3b *hidesrc,*hiddensrc;
  int i,j,k;
  int shift;
  int offset;
    hidden = cv::imread("hidden.bmp", 1);
    hide = cv::imread("hide.bmp", 1);
    
    if( hide.data == NULL || hidden.data == NULL) return -1;

    for(i = 0; i < 400; i++){
      hidesrc = hide.ptr<cv::Vec3b>(i);
      hiddensrc = hidden.ptr<cv::Vec3b>(i);

      for(j = 0; j < 100; j++){
    int shift = 0b11;
    for(k =0; k < 4; k++){
      //shiftdown for steg space
      offset = j*4+k;
      hiddensrc[offset][0] >>= 2;
      hiddensrc[offset][1] >>= 2;
      hiddensrc[offset][2] >>= 2;

      //assert info of hide img
      hiddensrc[offset][0] = (hiddensrc[offset][0] << 2) | ((hidesrc[j][0] & shift) >> (2*k));
      hiddensrc[offset][1] = (hiddensrc[offset][1] << 2) | ((hidesrc[j][1] & shift) >> (2*k));
      hiddensrc[offset][2] = (hiddensrc[offset][2] << 2) | ((hidesrc[j][2] & shift) >> (2*k));
      shift = shift << 2;
    }
      }
    }
    cv::imwrite("output.bmp", hidden);
    return 0;
}

dec.cc

#include "opencv2/highgui.hpp"
int main(){
  cv::Mat steged = cv::imread("output.bmp", 1);
  cv::Mat dec  = cv::Mat::zeros(400,100,CV_8UC3);
  cv::Vec3b *ssrc,*dsrc;
  int i,j,k;

  if( steged.data == NULL || dec.data == NULL) return -1;
  for(i = 0; i < 400; i++){
    ssrc = steged.ptr<cv::Vec3b>(i);
    dsrc = dec.ptr<cv::Vec3b>(i);
    for(j =0; j < 100; j++){
      for(k = 0; k < 4; k++){
    dsrc[j][0] += ((ssrc[j*4+k][0] & 3) << (2*k));
    dsrc[j][1] += ((ssrc[j*4+k][1] & 3) << (2*k));
    dsrc[j][2] += ((ssrc[j*4+k][2] & 3) << (2*k));
      }
    }
  }
  cv::imwrite("dec.bmp",dec);
  return 0;
}