RubyでのKoch-Zhaoステガノグラフィ法の実装

この記事では、さまざまな種類の攻撃に対する耐性の観点と、許容可能な画質を維持する観点の両方から、画像内の情報を隠す最も好ましいステガノグラフィ方法について説明します。



情報を埋め込むためのKoch-Zhaoアルゴリズムは、コンテナの周波数領域を使用し、離散コサイン変換(DCT)の係数の値の相対的な置換で構成されます。 画像は8×8ピクセルのブロックに分割され、DCTが各ブロックに適用されます。 各ブロックは、1ビットの情報を記録するのに適しています。



したがって、非表示アルゴリズムは次のようになります。



-8の増分でdouble配列を使用してイメージを反復処理します

-各反復で、8x8ピクセルの一時配列を作成します。各要素は3ピクセルの色のセットになります。

-この配列にDCTを適用し、サイズ8x8の係数の配列を取得します

-2つの係数を選択し、それらの差を法として計算する

-差が25以下の場合、最初の係数に2番目の+定数の正の値、または同じものにマイナス記号を付けます(これはビット転送と呼ばれます)

-差が-25以下の場合、同じアクションは2番目の係数にのみ適用されます。

-次に、逆DCTを適用して、係数を空間ドメインに戻します。

-次に、新しい色の値を画像にコピーします。



Ruby言語でのDCTおよびODKP関数の実装は次のとおりです。



def dct(dct,arr) s=0 (0..7).each do |i| (0..7).each do |j| temp = 0.0 (0..7).each do |x| (0..7).each do |y| temp = temp + $cos_t[i][x]*$cos_t[j][y]*arr[x][y][:blue] end end dct[i][j] = $e[i][j]*temp end end return dct end def idct(dct,arr) (0..7).each do |i| (0..7).each do |j| temp = 0 (0..7).each do |x| (0..7).each do |y| temp += dct[x][y]*$cos_t[x][i]*$cos_t[y][j]*$e[x][y] arr[i][j][:blue] = (temp > 255) ? 255 : (temp < 0 ) ? 0 : temp.round; end end end end return arr end
      
      







$ cos_tおよび$ eは、値がすでに設定されているグローバル配列変数です。



この方法は、大幅な変更に対しても画像の歪みに対しては非常に耐性がありますが、大量のデータを隠すのには適用できないことに注意してください。



情報の非表示/読み取りを実装するスクリプトの完全なコード:



 require 'RMagick' include Magick $cos_t = [ [1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0], [0.9807853, 0.8314696, 0.5555702, 0.1950903, -0.1950903,-0.5555702,-0.8314696,-0.9807853], [0.9238795, 0.3826834,-0.3826834,-0.9238795, -0.9238795,-0.3826834, 0.3826834, 0.9238795], [0.8314696,-0.1950903,-0.9807853,-0.5555702, 0.5555702, 0.9807853, 0.1950903,-0.8314696], [0.7071068,-0.7071068,-0.7071068, 0.7071068, 0.7071068,-0.7071068,-0.7071068, 0.7071068], [0.5555702,-0.9807853, 0.1950903, 0.8314696, -0.8314696,-0.1950903, 0.9807853,-0.5555702], [0.3826834,-0.9238795, 0.9238795,-0.3826834, -0.3826834, 0.9238795,-0.9238795, 0.3826834], [0.1950903,-0.5555702, 0.8314696,-0.9807853, 0.9807853,-0.8314696, 0.5555702,-0.1950903] ] $e = [ [0.125, 0.176777777, 0.176777777, 0.176777777, 0.176777777, 0.176777777, 0.176777777, 0.176777777], [0.176777777, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25], [0.176777777, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25], [0.176777777, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25], [0.176777777, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25], [0.176777777, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25], [0.176777777, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25], [0.176777777, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25]]; def insert_message(image,text) i = image.copy dct = Array.new(8).map!{Array.new(8)} k = 0 l = 0 s=0 temp = Array.new(8).map!{Array.new(8)} (0..(image.columns - 1)).step(8) do |i| (0..(image.rows - 1)).step(8) do |j| break if l >= text.length*8 (0..7).each do |x| (0..7).each do |y| temp[x][y] = { :red=>image.pixel_color(j+x,i+y).red, :green=>image.pixel_color(j+x,i+y).green, :blue=>image.pixel_color(j+x,i+y).blue } end end dct = dct(dct,temp) k = dct[3][4].abs - dct[4][3].abs if get_bit(text,l) if k<=25 dct[3][4] = (dct[3][4]>=0) ? dct[4][3].abs + 150 : -1*(dct[4][3].abs + 150) end else if k>=-25 dct[4][3] = (dct[4][3]>=0) ? dct[3][4].abs + 150 : -1*(dct[3][4].abs + 150) end end xt = temp.clone temp = idct(dct,temp) (0..7).each do |x| (0..7).each do |y| pixel = Pixel.new(temp[x][y][:red],temp[x][y][:green],temp[x][y][:blue]) image.pixel_color(j+x,i+y,pixel) end end l=l+1 end break if l >= text.length end image.write('cr.bmp') return image end def read_message(image) k = 0 s=0 out = [] l=0 a='' p=0 b=0 dct = Array.new(8).map!{Array.new(8)} temp = Array.new(8).map!{Array.new(8)} (0..(image.columns - 1)).step(8) do |i| (0..(image.rows - 1)).step(8) do |j| (0..7).each do |x| (0..7).each do |y| temp[x][y] = { :red=>image.pixel_color(j+x,i+y).red, :green=>image.pixel_color(j+x,i+y).green, :blue=>image.pixel_color(j+x,i+y).blue } end end l=l+1 dct = dct(dct,temp) k = dct[3][4].abs-dct[4][3].abs if k>=25 a=1 elsif k<=-25 a=0 else a=-1 break end b |= a << p if p==7 out.push(b.chr) b=0 end p=(p<7) ? p+1 : 0 end if a==-1 break end end return out.join end def dct(dct,arr) s=0 (0..7).each do |i| (0..7).each do |j| temp = 0.0 (0..7).each do |x| (0..7).each do |y| temp = temp + $cos_t[i][x]*$cos_t[j][y]*arr[x][y][:blue] end end dct[i][j] = $e[i][j]*temp end end return dct end def idct(dct,arr) (0..7).each do |i| (0..7).each do |j| temp = 0 (0..7).each do |x| (0..7).each do |y| temp += dct[x][y]*$cos_t[x][i]*$cos_t[y][j]*$e[x][y] arr[i][j][:blue] = (temp > 255) ? 255 : (temp < 0 ) ? 0 : temp.round; end end end end return arr end def get_bit(str,pos) return true if str[pos/8].ord & (1 << pos % 8) > 0 return false if str[pos/8].ord & (1 << pos % 8) <= 0 end image = Magick::Image.read('src.bmp').first insert_message(image,"qweqwe") image = Magick::Image.read('dst.bmp').first puts read_message image
      
      






All Articles