+++ /dev/null
-#-*- coding:utf-8 -*-
-import Image as im
-import numpy
-from sys import argv
-from pylab import *
-import string
-import cv
-import os
-from random import *
-from math import *
-
-infinity = 1000000000
-
-
-#paths for cover and stego
-path_stego = '/home/couturie/ajeter/stego/'
-path_cover = '/home/couturie/ajeter/cover/'
-
-# forward part
-
-
-def dec(ch,n):
- l = len(ch)
- acc = 0
- for i in xrange(l):
- if ch[i]==1:
- acc = acc + 2**(n-i-1)
- return acc
-
-
-def bin(elem,n):
- """Convertit un nombre en binaire"""
- q = -1
- res = [0 for i in xrange(n)]
- i = 1
- while q != 0:
- q = elem // 2
- r = elem % 2
- res[n-i] = r
- elem = q
- i+=1
- return res
-
-
-
-def xorb(a,b):
- return 1 if a != b else 0
-
-def xor(e1,e2,h):
- e1b,e2b = bin(e1,h),bin(e2,h)
- d = dec([xorb(e1b[j],e2b[j]) for j in xrange(h)],h)
- return d
-
-def lit(d,(indx,indy)):
- if (indx,indy) in d :
- return d[(indx,indy)]
- else :
- return 0
-
-
-
-
-def forward(H_hat,x,message,lnm,rho):
- (h,w) = int(log(max(H_hat),2))+1, len(H_hat)
- path = dict()
- nbblock = lnm
- wght = [infinity for _ in xrange(int(2**h))]
- wght[0]=0
- newwght = [0 for _ in xrange(int(2**h))]
-# rho = 1
-# rho= [1 for _ in xrange(len(x))]
- indx,indm = 0,0
- i=0
- while i < nbblock: # pour chaque bit du message
- for j in xrange(w): # pour chaque colonne de H_hat
- #print indx, "en entrant",wght
- k = 0
- while k < int(2**h): # pour chaque ligne de H
- w0 = wght[k] + x[indx]*rho[indx]
- w1 = wght[xor(k,H_hat[j],h)] + (1-x[indx])*rho[indx]
- if w1 < w0 :
- path[(indx,k)] = 1
- else :
- if (indx,k) in path:
- del path[(indx,k)]
- newwght[k] = min(w0,w1)
- k +=1
- indx +=1
- wght = [t for t in newwght]
- #print " apres calcul",wght
-
- for j in xrange(int(2**(h-1))): # pour chaque colonne de H
- wght[j] = wght[2*j + message[indm]]
- wght = wght[:int(pow(2,h-1))] + [infinity for _ in xrange(int(pow(2,h)-pow(2,h-1)))]
- indm +=1
- i +=1
- start = np.argmin(wght)
- return (start,path)
-
-
-def backward(start,H_hat,x,message,lnm,path):
- (h,w) = int(log(max(H_hat),2))+1, len(H_hat)
- indx,indm = len(x)-1,lnm-1
- state = 2*start + message[indm]
- indm -=1
- # l'initialisation de state n'est pas optimale...
- nbblock = lnm
- y=np.zeros(len(x))
- i=0
- while i < nbblock:
- l = range(w)
- l.reverse()
- for j in l: # pour chaque colonne de H_hat
- y[indx] = lit(path,(indx,state))
- state = xor(state,y[indx]*H_hat[j],h)
- indx -=1
- state = 2*state + message[indm]
- indm -=1
- i +=1
- return [int(t) for t in y]
-
-
-
-
-
-
-def trouve_H_hat(n,m,h):
- assert h ==7
- alpha = float(n)/m
- assert alpha >= 1
- index = min(int(alpha),9)
- mat = {
- 1 : [127],
- 2 : [71,109],
- 3 : [95, 101, 121],
- 4 : [81, 95, 107, 121],
- 5 : [75, 95, 97, 105, 117],
- 6 : [73, 83, 95, 103, 109, 123],
- 7 : [69, 77, 93, 107, 111, 115, 121],
- 8 : [69, 79, 81, 89, 93, 99, 107, 119],
- 9 : [69, 79, 81, 89, 93, 99, 107, 119, 125]
- }[index]
- return(mat, index*m)
-
-
-def stc(x,rho,message):
- lnm = len(message)
- (mat,taille_suff) = trouve_H_hat(len(x),len(message),7)
- x_b = x[:taille_suff]
- (start,path) = forward(mat,x_b,message,lnm,rho)
- return (x_b,backward(start,mat,x_b,message,lnm,path),mat)
-
-
-
-
-
-def nbdif(x,y):
- r,it = 0,0
- l = len(y)
- while it < l :
- if x[it] != y[it] :
- r +=1
- it += 1
- return float(r)/l
-
-
-
-
-
-
-def prod(H_hat,lnm,y):
- (h,w) = int(log(max(H_hat),2))+1, len(H_hat)
- i=0
- H =[]
- V=[0 for _ in range(len(y))]
- sol=[]
- while i < lnm: # pour chaque ligne
- V=[0 for _ in range(len(y))]
- k = max([(i-h+1)*w,0])
- dec = max([i-h+1,0])
- for j in xrange(min([i+1,h])): #nbre de blocks presents sur la ligne i
- for l in xrange(w): # pour chaque collone de H_hat
- V[k] = bin(H_hat[l],h)[h-i-1+j+dec]
- k+=1
-
- sol.append(np.dot(np.array(V),np.array(y)))
- i+=1
- #H += [V]
- #H = np.array(H)
- #y = np.array(y)
- #print "dot",np.dot(H,y),H.shape
- #print "sol",sol
- return sol#list(np.dot(H,y))
-
-def equiv(x,y):
- lx = len(x)
- assert lx == len(y)
- i=0
- while i < lx :
- if x[i] % 2 != y[i]%2 :
- return False
- i += 1
- return True
-
-
-
-
-
-
-def conversion(nombre, base, epsilon = 0.00001 ):
- ''' Soit nombre écrit en base 10, le retourne en base base'''
- if not 2 <= base <= 36:
- raise ValueError, "La base doit être entre 2 et 36"
- if not base == 2 and '.' in str(nombre):
- raise ValueError, "La partie décimale n'est pas gérée pour les bases\
- différentes de 2."
- # IMPROVE : Convertir aussi la partie décimale, quand la base n'est pas égale
- # à 2.
- abc = string.digits + string.letters
- result = ''
- if nombre < 0:
- nombre = -nombre
- sign = '-'
- else:
- sign = ''
- if '.' in str(nombre):
- entier,decimal = int(str(nombre).split('.')[0]),\
- float('.'+str(nombre).split('.')[1])
- else:
- entier,decimal = int(str(nombre)),0
- while entier !=0 :
- entier, rdigit = divmod( entier, base )
- result = abc[rdigit] + result
- flotante, decimalBin = 1./float(base),''
- while flotante > epsilon :
- if decimal >= flotante:
- decimalBin+='1'
- decimal-=flotante
- else :
- decimalBin+='0'
- flotante = flotante/float(base)
- if '1' in decimalBin :
- reste = '.'+decimalBin
- while reste[-1]=='0':
- reste = reste[:-1]
- else :
- reste = ''
- return sign + result + reste
-
-
-def getBit(X,pos):
- '''Récupère le bit en position pos de X.
- Par exemple, getBit(8,1) = 0, puisque le bit le plus à droite de 8 = 1000 est 0.
- On fera attention à ce que :
- - on compte à partir du point,
- - l'élément juste à gauche du point est en position 1,
- - celui juste à droite est en position -1.'''
- assert pos != 0
- entier = conversion(X,2)
- if '.' in entier:
- entier, decimal = entier.split('.')
- if decimal == '0':
- decimal = ''
- else:
- decimal = ''
- if '-' in entier:
- entier = entier.replace('-','')
- entier = entier.zfill(abs(pos))
- decimal = (decimal+'0'*abs(pos))[:max(len(decimal),abs(pos))]
-
- return int(entier[len(entier)-pos]) if pos >0 else int(decimal[-pos-1])
-
-
-def setBit(X,pos,y):
- '''Fixe le bit pos de X à la valeur y.
- Le fonctionnement est similaire à getBit :
- - on compte à partir du point,
- - l'élément juste à gauche du point est en position 1,
- - celui juste à droite est en position -1.'''
- assert pos != 0
- entier = conversion(X,2)
- if '.' in entier:
- entier, decimal = entier.split('.')
- else:
- decimal = ''
- entier = list(entier.zfill(abs(pos)))
- decimal = list((decimal+'0'*abs(pos))[:max(len(decimal),abs(pos))])
- if pos>0:
- entier[len(entier)-pos]=str(int(y))
- else:
- decimal[-pos-1] = str(int(y))
- if decimal == []:
- return int(''.join(entier),2)
- else:
- S=0
- for k in range(len(decimal)):
- S += 1./2**(k+1)*int(decimal[k])
- return float(str(int(''.join(entier),2))+'.'+str(S).split('.')[1])
-
-
-def a2b(a):
- ai = ord(a)
- return ''.join('01'[(ai >> x) & 1] for x in xrange(7, -1, -1))
-
-
-
-def a2b_list(L):
- LL=[]
- for i in L:
- for j in list(a2b(i)):
- LL.append(j)
- return LL
-
-
-
-def toDecimal(x):
- return sum(map(lambda z: int(x[z]) and 2**(len(x) - z - 1),
- range(len(x)-1, -1, -1)))
-
-def conv_list_bit(L):
- L2=[]
- for j in range(len(L)/8):
- L2.append(chr(toDecimal("".join(L[j*8:(j+1)*8]))))
- return ''.join(L2)
-
-def Denary2Binary(n):
- '''convert denary integer n to binary string bStr'''
- bStr = ''
- if n < 0: raise ValueError, "must be a positive integer"
- if n == 0: return '0'
- while n > 0:
- bStr = str(n % 2) + bStr
- n = n >> 1
- return bStr
-
-
-def compute_filter_sobel(level,image):
- level2=level.copy()
- level2= array(level2.getdata()).flatten()
- l=0
- for x in level2:
- level2[l]=(x/2)*2
- l+=1
- level2_im=im.new('L',image.size)
- level2_im.putdata(level2)
-
- cv_im = cv.CreateImageHeader(image.size, cv.IPL_DEPTH_8U, 1)
- cv.SetData(cv_im, level2_im.tostring())
- dst16 = cv.CreateImage(cv.GetSize(cv_im), cv.IPL_DEPTH_16S, 1)
-
- laplace = cv.Sobel(cv_im, dst16,1, 1,7)
-
- dst8 = cv.CreateImage (cv.GetSize(cv_im), cv.IPL_DEPTH_8U, 1)
- cv.ConvertScale(dst16,dst8)
- processed=im.fromstring("L", cv.GetSize(dst8), dst8.tostring())
-# cv.ShowImage ('canny', dst8)
-# cv.WaitKey()
-
- return processed
-
-
-
-def compute_list_bit_to_change(threshold,processed):
- List=[]
- nb=0
- l=0
- for i in processed:
- if (processed[l]>=threshold):
- #if nb%2==0:
- List.append(l)
- #nb+=1
- l+=1
- return List
-
-
-def compute_filter_canny(level,image):
- level2=level.copy()
- level2= array(level2.getdata()).flatten()
- l=0
- for x in level2:
- level2[l]=(x/2)*2
- l+=1
- level2_im=im.new('L',image.size)
- level2_im.putdata(level2)
- level2_im=im.merge("RGB",(level2_im,level2_im,level2_im))
-
- mean=numpy.mean(level2)
- std=numpy.std(level2)
-
- cv_im = cv.CreateImageHeader(image.size, cv.IPL_DEPTH_8U, 3)
- cv.SetData(cv_im, level2_im.tostring())
-
- yuv = cv.CreateImage(cv.GetSize(cv_im), 8, 3)
- gray = cv.CreateImage(cv.GetSize(cv_im), 8, 1)
- cv.CvtColor(cv_im, yuv, cv.CV_BGR2YCrCb)
- cv.Split(yuv, gray, None, None, None)
-
- canny = cv.CreateImage(cv.GetSize(cv_im), 8, 1)
-
- List_bit_to_change=set([])
- Weight=[]
-
-
-
- cv.Canny(gray, canny, mean-1*std, mean+1*std,3) #avant 10 255
- processed=im.fromstring("L", cv.GetSize(canny), canny.tostring())
- processed= array(processed.getdata()).flatten()
- List3=set(compute_list_bit_to_change(100,processed))
-
- cv.Canny(gray, canny, mean-1*std, mean+1*std,5) #avant 10 255
- processed=im.fromstring("L", cv.GetSize(canny), canny.tostring())
- processed= array(processed.getdata()).flatten()
- List5=set(compute_list_bit_to_change(100,processed))
-
- cv.Canny(gray, canny, mean-1*std, mean+1*std,7) #avant 10 255
- processed=im.fromstring("L", cv.GetSize(canny), canny.tostring())
- processed= array(processed.getdata()).flatten()
- List7=set(compute_list_bit_to_change(100,processed))
-
- nb_bit_embedded=(512*512/10)+40
- AvailablePixel3=List3
- AvailablePixel5=AvailablePixel3.union(List5)
- AvailablePixel7=AvailablePixel5.union(List7)
- if len(AvailablePixel3)>nb_bit_embedded:
- step=1
- WorkingPixel=AvailablePixel3
- elif len(AvailablePixel5)>nb_bit_embedded:
- step=2
- WorkingPixel=AvailablePixel5
- elif len(AvailablePixel7)>nb_bit_embedded:
- step=3
- WorkingPixel=AvailablePixel7
- else:
- step=4
- WorkingPixel=range(len(level2))
-
- print "avail P3",len(AvailablePixel3)
- print "avail P5",len(AvailablePixel5)
- print "avail P7",len(AvailablePixel7)
-
- print "size WorkingPixel",len(WorkingPixel)
- Weight=[0 for _ in WorkingPixel]
-
- l=0
- for i in WorkingPixel:
- if step>=1 and i in List3:
- Weight[l]=1
- if step>=2 and i in List5 and Weight[l]==0:
- Weight[l]=10
- if step>=3 and i in List7 and Weight[l]==0:
- Weight[l]=100
- if step>=4 and Weight[l]==0:
- Weight[l]=1000
- l+=1
-
-
-
-
- List_bit_to_change=WorkingPixel
-
-
-
-
-
- return [List_bit_to_change,Weight]
-
-
-
-
-
-
-
-
-
-
-
-def mystego(filein, fileout):
- dd = im.open(filein)
- dd = dd.convert('RGB')
- red, green, blue = dd.split()
- level=red.copy()
-
- [List_bit_to_change,Weight]=compute_filter_canny(level,dd)
- level= array(level.getdata()).flatten()
-
-
- bit_to_read=1
-
-
-
-
-
-
-#parameters for BBS
- M=18532395500947174450709383384936679868383424444311405679463280782405796233163977*39688644836832882526173831577536117815818454437810437210221644553381995813014959
- X=18532395500947174450709383384936679868383424444311
-
-
-
-
-
-
- l=0
-
-
-
- message="Salut christophe, arrives tu à lire ce message? normalement tu dois lire cela. Bon voici un test avec un message un peu plus long. Bon j'en rajoute pour voir. Ce que j'écris est très original... Bref, je suis un poete Salut christophe, arrives tu à lire ce message? normalement tu dois lire cela. Bon voici un test avec un message un peu plus long. Bon j'en rajoute pour voir. Ce que j'écris est très original... Bref, je suis un poete Salut christophe, arrives tu à lire ce message? normalement tu dois lire cela. Bon voici un test avec un message un peu plus long. Bon j'en rajoute pour voir. Ce que j'écris est très original... Bref, je suis un poete Salut christophe, arrives tu à lire ce message? normalement tu dois lire cela. Bon voici un test avec un message un peu plus long. Bon j'en rajoute pour voir. Ce que j'écris est très original... Bref, je suis un poete Salut christophe, arrives tu à lire ce message? normalement tu dois lire cela. Bon voici un test avec un message un peu plus long. Bon j'en rajoute pour voir. Ce que j'écris est très original... Bref, je suis un poete Salut christophe, arrives tu à lire ce message? normalement tu dois lire cela. Bon voici un test avec un message un peu plus long. Bon j'en rajoute pour voir. Ce que j'écris est très original... Bref, je suis un poete Salut christophe, arrives tu à lire ce message? normalement tu dois lire cela. Bon voici un test avec un message un peu plus long. Bon j'en rajoute pour voir. Ce que j'écris est très original... Bref, je suis un poete Salut christophe, arrives tu à lire ce message? normalement tu dois lire cela. Bon voici un test avec un message un peu plus long. Bon j'en rajoute pour voir. Ce que j'écris est très original... Bref, je suis un poete Salut christophe, arrives tu à lire ce message? normalement tu dois lire cela. Bon voici un test avec un message un peu plus long. Bon j'en rajoute pour voir. Ce que j'écris est très original... Bref, je suis un poete Salut christophe, arrives tu à lire ce message? normalement tu dois lire cela. Bon voici un test avec un message un peu plus long. Bon j'en rajoute pour voir. Ce que j'écris est très original... Bref, je suis un poete Salut christophe, arrives tu à lire ce message? normalement tu dois lire cela. Bon voici un test avec un message un peu plus long. Bon j'en rajoute pour voir. Ce que j'écris est très original... Bref, je suis un poete Salut christophe, arrives tu à lire ce message? normalement tu dois lire cela. Bon voici un test avec un message un peu plus long. Bon j'en rajoute pour voir. Ce que j'écris est très original... Bref, je suis un poete Ce que j'écris est très original... Bref, je suis un poete Salut christophe, arrives tu à lire ce message? normalement tu dois lire cela. Bon voici un test avec un message un peu plus long. Bon j'en rajoute pour voir. Ce que j'écris est très original... Bref, je suis un poete Ce que j'écris est très original... Bref, je suis un poete Salut christophe, arrives tu à lire ce message? normalement tu dois lire cela. Bon voici un test avec un message un peu plus long. Bon j'en rajoute pour voir. Ce que j'écris est très original... Bref, je suis un poete voila c'est la fin blablabla:-)"
- message=message[0:len(message)/1]
- leng_msg=len(message)
- message=message+((leng_msg+7)/8*8-leng_msg)*" "
- leng_msg=len(message)
-
- leng='%08d'%len(message)
-
-
-
-
- len_leng=len(leng)
- leng_error=int(len_leng)
- leng_cor=leng
- List_pack=a2b_list(leng_cor)
-
- List_random=[]
- while len(List_random)<len(List_bit_to_change):
- X=(X*X)%M
- List_random.extend(Denary2Binary(X))
-
- size=0
- for i in range(leng_msg/8):
- m=message[i*8:(i+1)*8]
- m_cor=m
- m_bin=a2b_list(m_cor)
- size=size+len(m_bin)
- List_pack.extend(m_bin)
-
-
-
-
-
-
-
-
- Support=[getBit(level[l],bit_to_read) for l in List_bit_to_change]
-
-
- Message=[(int(List_pack[l])^int(List_random[l])) for l in xrange(len(List_pack))]
-
- print "support",len(List_bit_to_change)
- print "message",len(Message)
- print "weight",len(Weight)
-
- (x_b,Stc_message,H_hat) = stc(Support,Weight,Message)
-
- print "pourcentage modif",nbdif(x_b,Stc_message)
- print "taille Stc_message",len(Stc_message)
-
-
-
- l=0
- size_mesg=0
- val_mod=0
-
-
-
- for l in List_bit_to_change:
- if(size_mesg<len(Stc_message)):
- b=getBit(level[l],bit_to_read)
- if b!=Stc_message[size_mesg]:
- val_mod+=1
- level[l]=float64(setBit(level[l],bit_to_read,Stc_message[size_mesg]))
- size_mesg+=1
-
- print 'size mesg',size_mesg
- print 'val mod',val_mod
- print 'len message',len(Message),len(List_pack)
-
-
-
- zz3=im.new('L',dd.size)
- zz3.putdata(level)
-
- zz3.save(fileout)
-
-
-
-
-listing = os.listdir(path_cover)
-
-print listing
-
-list_nb_bit=[]
-l=0
-
-
-
-for infile in listing:
- print "current file is: " + infile, path_stego+infile
- mystego(path_cover+infile,path_stego+infile)
- l+=1
-
+++ /dev/null
-#-*- coding:utf-8 -*-
-import Image as im
-import numpy
-from sys import argv
-from pylab import *
-import string
-import cv
-import os
-from random import *
-from math import *
-
-infinity = 1000000000
-
-path_stego = '/home/couturie/ajeter/stego/'
-path_cover = '/home/couturie/ajeter/cover/'
-
-
-# forward part
-
-
-def dec(ch,n):
- l = len(ch)
- acc = 0
- for i in xrange(l):
- if ch[i]==1:
- acc = acc + 2**(n-i-1)
- return acc
-
-
-def bin(elem,n):
- """Convertit un nombre en binaire"""
- q = -1
- res = [0 for i in xrange(n)]
- i = 1
- while q != 0:
- q = elem // 2
- r = elem % 2
- res[n-i] = r
- elem = q
- i+=1
- return res
-
-
-
-def xorb(a,b):
- return 1 if a != b else 0
-
-def xor(e1,e2,h):
- e1b,e2b = bin(e1,h),bin(e2,h)
- d = dec([xorb(e1b[j],e2b[j]) for j in xrange(h)],h)
- return d
-
-def lit(d,(indx,indy)):
- if (indx,indy) in d :
- return d[(indx,indy)]
- else :
- return 0
-
-
-
-
-def forward(H_hat,x,message,lnm,rho):
- (h,w) = int(log(max(H_hat),2))+1, len(H_hat)
- path = dict()
- nbblock = lnm
- wght = [infinity for _ in xrange(int(2**h))]
- wght[0]=0
- newwght = [0 for _ in xrange(int(2**h))]
-# rho = 1
-# rho= [1 for _ in xrange(len(x))]
- indx,indm = 0,0
- i=0
- while i < nbblock: # pour chaque bit du message
- for j in xrange(w): # pour chaque colonne de H_hat
- #print indx, "en entrant",wght
- k = 0
- while k < int(2**h): # pour chaque ligne de H
- w0 = wght[k] + x[indx]*rho[indx]
- w1 = wght[xor(k,H_hat[j],h)] + (1-x[indx])*rho[indx]
- if w1 < w0 :
- path[(indx,k)] = 1
- else :
- if (indx,k) in path:
- del path[(indx,k)]
- newwght[k] = min(w0,w1)
- k +=1
- indx +=1
- wght = [t for t in newwght]
- #print " apres calcul",wght
-
- for j in xrange(int(2**(h-1))): # pour chaque colonne de H
- wght[j] = wght[2*j + message[indm]]
- wght = wght[:int(pow(2,h-1))] + [infinity for _ in xrange(int(pow(2,h)-pow(2,h-1)))]
- indm +=1
- i +=1
- start = np.argmin(wght)
- return (start,path)
-
-
-def backward(start,H_hat,x,message,lnm,path):
- (h,w) = int(log(max(H_hat),2))+1, len(H_hat)
- indx,indm = len(x)-1,lnm-1
- state = 2*start + message[indm]
- indm -=1
- # l'initialisation de state n'est pas optimale...
- nbblock = lnm
- y=np.zeros(len(x))
- i=0
- while i < nbblock:
- l = range(w)
- l.reverse()
- for j in l: # pour chaque colonne de H_hat
- y[indx] = lit(path,(indx,state))
- state = xor(state,y[indx]*H_hat[j],h)
- indx -=1
- state = 2*state + message[indm]
- indm -=1
- i +=1
- return [int(t) for t in y]
-
-
-
-
-
-
-def trouve_H_hat(n,m,h):
- assert h ==7
- alpha = float(n)/m
- assert alpha >= 1
- index = min(int(alpha),9)
- mat = {
- 1 : [127],
- 2 : [71,109],
- 3 : [95, 101, 121],
- 4 : [81, 95, 107, 121],
- 5 : [75, 95, 97, 105, 117],
- 6 : [73, 83, 95, 103, 109, 123],
- 7 : [69, 77, 93, 107, 111, 115, 121],
- 8 : [69, 79, 81, 89, 93, 99, 107, 119],
- 9 : [69, 79, 81, 89, 93, 99, 107, 119, 125]
- }[index]
- return(mat, index*m)
-
-
-def stc(x,rho,message):
- lnm = len(message)
- (mat,taille_suff) = trouve_H_hat(len(x),len(message),7)
- x_b = x[:taille_suff]
- (start,path) = forward(mat,x_b,message,lnm,rho)
- return (x_b,backward(start,mat,x_b,message,lnm,path),mat)
-
-
-
-
-
-def nbdif(x,y):
- r,it = 0,0
- l = len(y)
- while it < l :
- if x[it] != y[it] :
- r +=1
- it += 1
- return float(r)/l
-
-
-
-
-
-
-def prod(H_hat,lnm,y):
- (h,w) = int(log(max(H_hat),2))+1, len(H_hat)
- i=0
- H =[]
- V=[0 for _ in range(len(y))]
- sol=[]
- while i < lnm: # pour chaque ligne
- V=[0 for _ in range(len(y))]
- k = max([(i-h+1)*w,0])
- dec = max([i-h+1,0])
- for j in xrange(min([i+1,h])): #nbre de blocks presents sur la ligne i
- for l in xrange(w): # pour chaque collone de H_hat
- V[k] = bin(H_hat[l],h)[h-i-1+j+dec]
- k+=1
-
- sol.append(np.dot(np.array(V),np.array(y)))
- i+=1
- #H += [V]
- #H = np.array(H)
- #y = np.array(y)
- #print "dot",np.dot(H,y),H.shape
- #print "sol",sol
- return sol#list(np.dot(H,y))
-
-def equiv(x,y):
- lx = len(x)
- assert lx == len(y)
- i=0
- while i < lx :
- if x[i] % 2 != y[i]%2 :
- return False
- i += 1
- return True
-
-
-
-
-
-
-def conversion(nombre, base, epsilon = 0.00001 ):
- ''' Soit nombre écrit en base 10, le retourne en base base'''
- if not 2 <= base <= 36:
- raise ValueError, "La base doit être entre 2 et 36"
- if not base == 2 and '.' in str(nombre):
- raise ValueError, "La partie décimale n'est pas gérée pour les bases\
- différentes de 2."
- # IMPROVE : Convertir aussi la partie décimale, quand la base n'est pas égale
- # à 2.
- abc = string.digits + string.letters
- result = ''
- if nombre < 0:
- nombre = -nombre
- sign = '-'
- else:
- sign = ''
- if '.' in str(nombre):
- entier,decimal = int(str(nombre).split('.')[0]),\
- float('.'+str(nombre).split('.')[1])
- else:
- entier,decimal = int(str(nombre)),0
- while entier !=0 :
- entier, rdigit = divmod( entier, base )
- result = abc[rdigit] + result
- flotante, decimalBin = 1./float(base),''
- while flotante > epsilon :
- if decimal >= flotante:
- decimalBin+='1'
- decimal-=flotante
- else :
- decimalBin+='0'
- flotante = flotante/float(base)
- if '1' in decimalBin :
- reste = '.'+decimalBin
- while reste[-1]=='0':
- reste = reste[:-1]
- else :
- reste = ''
- return sign + result + reste
-
-
-def getBit(X,pos):
- '''Récupère le bit en position pos de X.
- Par exemple, getBit(8,1) = 0, puisque le bit le plus à droite de 8 = 1000 est 0.
- On fera attention à ce que :
- - on compte à partir du point,
- - l'élément juste à gauche du point est en position 1,
- - celui juste à droite est en position -1.'''
- assert pos != 0
- entier = conversion(X,2)
- if '.' in entier:
- entier, decimal = entier.split('.')
- if decimal == '0':
- decimal = ''
- else:
- decimal = ''
- if '-' in entier:
- entier = entier.replace('-','')
- entier = entier.zfill(abs(pos))
- decimal = (decimal+'0'*abs(pos))[:max(len(decimal),abs(pos))]
-
- return int(entier[len(entier)-pos]) if pos >0 else int(decimal[-pos-1])
-
-
-def setBit(X,pos,y):
- '''Fixe le bit pos de X à la valeur y.
- Le fonctionnement est similaire à getBit :
- - on compte à partir du point,
- - l'élément juste à gauche du point est en position 1,
- - celui juste à droite est en position -1.'''
- assert pos != 0
- entier = conversion(X,2)
- if '.' in entier:
- entier, decimal = entier.split('.')
- else:
- decimal = ''
- entier = list(entier.zfill(abs(pos)))
- decimal = list((decimal+'0'*abs(pos))[:max(len(decimal),abs(pos))])
- if pos>0:
- entier[len(entier)-pos]=str(int(y))
- else:
- decimal[-pos-1] = str(int(y))
- if decimal == []:
- return int(''.join(entier),2)
- else:
- S=0
- for k in range(len(decimal)):
- S += 1./2**(k+1)*int(decimal[k])
- return float(str(int(''.join(entier),2))+'.'+str(S).split('.')[1])
-
-
-def a2b(a):
- ai = ord(a)
- return ''.join('01'[(ai >> x) & 1] for x in xrange(7, -1, -1))
-
-
-
-def a2b_list(L):
- LL=[]
- for i in L:
- for j in list(a2b(i)):
- LL.append(j)
- return LL
-
-
-
-def toDecimal(x):
- return sum(map(lambda z: int(x[z]) and 2**(len(x) - z - 1),
- range(len(x)-1, -1, -1)))
-
-def conv_list_bit(L):
- L2=[]
- for j in range(len(L)/8):
- L2.append(chr(toDecimal("".join(L[j*8:(j+1)*8]))))
- return ''.join(L2)
-
-def Denary2Binary(n):
- '''convert denary integer n to binary string bStr'''
- bStr = ''
- if n < 0: raise ValueError, "must be a positive integer"
- if n == 0: return '0'
- while n > 0:
- bStr = str(n % 2) + bStr
- n = n >> 1
- return bStr
-
-
-def compute_filter_sobel(level,image):
- level2=level.copy()
- level2= array(level2.getdata()).flatten()
- l=0
- for x in level2:
- level2[l]=(x/2)*2
- l+=1
- level2_im=im.new('L',image.size)
- level2_im.putdata(level2)
-
- cv_im = cv.CreateImageHeader(image.size, cv.IPL_DEPTH_8U, 1)
- cv.SetData(cv_im, level2_im.tostring())
- dst16 = cv.CreateImage(cv.GetSize(cv_im), cv.IPL_DEPTH_16S, 1)
-
- laplace = cv.Sobel(cv_im, dst16,1, 1,7)
-
- dst8 = cv.CreateImage (cv.GetSize(cv_im), cv.IPL_DEPTH_8U, 1)
- cv.ConvertScale(dst16,dst8)
- processed=im.fromstring("L", cv.GetSize(dst8), dst8.tostring())
-# cv.ShowImage ('canny', dst8)
-# cv.WaitKey()
-
- return processed
-
-
-
-def compute_list_bit_to_change(threshold,processed):
- List=[]
- nb=0
- l=0
- for i in processed:
- if (processed[l]>=threshold):
- #if nb%2==0:
- List.append(l)
- #nb+=1
- l+=1
- return List
-
-
-def compute_filter_canny(level,image):
- level2=level.copy()
- level2= array(level2.getdata()).flatten()
- l=0
- for x in level2:
- level2[l]=(x/2)*2
- l+=1
- level2_im=im.new('L',image.size)
- level2_im.putdata(level2)
- level2_im=im.merge("RGB",(level2_im,level2_im,level2_im))
-# histo=level2_im.histogram()
- mean=numpy.mean(level2)
- std=numpy.std(level2)
-
- cv_im = cv.CreateImageHeader(image.size, cv.IPL_DEPTH_8U, 3)
- cv.SetData(cv_im, level2_im.tostring())
-
- yuv = cv.CreateImage(cv.GetSize(cv_im), 8, 3)
- gray = cv.CreateImage(cv.GetSize(cv_im), 8, 1)
- cv.CvtColor(cv_im, yuv, cv.CV_BGR2YCrCb)
- cv.Split(yuv, gray, None, None, None)
- #print 'mean',mean
- #print 'std',std
-
- canny = cv.CreateImage(cv.GetSize(cv_im), 8, 1)
-
- List_bit_to_change=set([])
- Weight=[]
-
-
-
- cv.Canny(gray, canny, mean-1*std, mean+1*std,3) #avant 10 255
- processed=im.fromstring("L", cv.GetSize(canny), canny.tostring())
- processed= array(processed.getdata()).flatten()
- List3=set(compute_list_bit_to_change(100,processed))
-
- cv.Canny(gray, canny, mean-1*std, mean+1*std,5) #avant 10 255
- processed=im.fromstring("L", cv.GetSize(canny), canny.tostring())
- processed= array(processed.getdata()).flatten()
- List5=set(compute_list_bit_to_change(100,processed))
-
- cv.Canny(gray, canny, mean-1*std, mean+1*std,7) #avant 10 255
- processed=im.fromstring("L", cv.GetSize(canny), canny.tostring())
- processed= array(processed.getdata()).flatten()
- List7=set(compute_list_bit_to_change(100,processed))
-
- nb_bit_embedded=len(List3)/2
- AvailablePixel3=List3
- AvailablePixel5=AvailablePixel3.union(List5)
- AvailablePixel7=AvailablePixel5.union(List7)
- if len(AvailablePixel3)>nb_bit_embedded:
- step=1
- WorkingPixel=AvailablePixel3
- elif len(AvailablePixel5)>nb_bit_embedded:
- step=2
- WorkingPixel=AvailablePixel5
- elif len(AvailablePixel7)>nb_bit_embedded:
- step=3
- WorkingPixel=AvailablePixel7
- else:
- step=4
- WorkingPixel=range(len(level2))
-
-
-
- print "avail P3",len(AvailablePixel3)
- print "avail P5",len(AvailablePixel5)
- print "avail P7",len(AvailablePixel7)
-
- print "size WorkingPixel",len(WorkingPixel)
- Weight=[0 for _ in WorkingPixel]
-
- l=0
- for i in WorkingPixel:
- if step>=1 and i in List3:
- Weight[l]=1
- if step>=2 and i in List5 and Weight[l]==0:
- Weight[l]=10
- if step>=3 and i in List7 and Weight[l]==0:
- Weight[l]=100
- if step>=4 and Weight[l]==0:
- Weight[l]=1000
- l+=1
-
-
-
-
- List_bit_to_change=WorkingPixel
-
-
-
- Size_message=nb_bit_embedded
-
- return [Size_message,Weight,List3]
-
-
-
-
-
-
-
-
-
-
-
-def mystego(filein, fileout):
- dd = im.open(filein)
- dd = dd.convert('RGB')
- red, green, blue = dd.split()
- level=red.copy()
-
- [Size_message,Weight,List_support]=compute_filter_canny(level,dd)
- level= array(level.getdata()).flatten()
-
-
- bit_to_read=1
-
-
-#parameters for BBS
- M=18532395500947174450709383384936679868383424444311405679463280782405796233163977*39688644836832882526173831577536117815818454437810437210221644553381995813014959
- X=18532395500947174450709383384936679868383424444311
-
-
-
-
-
-
-
-
- l=0
-
-
-
- message="Salut christophe, arrives tu à lire ce message? normalement tu dois lire cela. Bon voici un test avec un message un peu plus long. Bon j'en rajoute pour voir. Ce que j'écris est très original... Bref, je suis un poete Salut christophe, arrives tu à lire ce message? normalement tu dois lire cela. Bon voici un test avec un message un peu plus long. Bon j'en rajoute pour voir. Ce que j'écris est très original... Bref, je suis un poete Salut christophe, arrives tu à lire ce message? normalement tu dois lire cela. Bon voici un test avec un message un peu plus long. Bon j'en rajoute pour voir. Ce que j'écris est très original... Bref, je suis un poete Salut christophe, arrives tu à lire ce message? normalement tu dois lire cela. Bon voici un test avec un message un peu plus long. Bon j'en rajoute pour voir. Ce que j'écris est très original... Bref, je suis un poete Salut christophe, arrives tu à lire ce message? normalement tu dois lire cela. Bon voici un test avec un message un peu plus long. Bon j'en rajoute pour voir. Ce que j'écris est très original... Bref, je suis un poete Salut christophe, arrives tu à lire ce message? normalement tu dois lire cela. Bon voici un test avec un message un peu plus long. Bon j'en rajoute pour voir. Ce que j'écris est très original... Bref, je suis un poete Salut christophe, arrives tu à lire ce message? normalement tu dois lire cela. Bon voici un test avec un message un peu plus long. Bon j'en rajoute pour voir. Ce que j'écris est très original... Bref, je suis un poete Salut christophe, arrives tu à lire ce message? normalement tu dois lire cela. Bon voici un test avec un message un peu plus long. Bon j'en rajoute pour voir. Ce que j'écris est très original... Bref, je suis un poete Salut christophe, arrives tu à lire ce message? normalement tu dois lire cela. Bon voici un test avec un message un peu plus long. Bon j'en rajoute pour voir. Ce que j'écris est très original... Bref, je suis un poete Salut christophe, arrives tu à lire ce message? normalement tu dois lire cela. Bon voici un test avec un message un peu plus long. Bon j'en rajoute pour voir. Ce que j'écris est très original... Bref, je suis un poete Salut christophe, arrives tu à lire ce message? normalement tu dois lire cela. Bon voici un test avec un message un peu plus long. Bon j'en rajoute pour voir. Ce que j'écris est très original... Bref, je suis un poete Salut christophe, arrives tu à lire ce message? normalement tu dois lire cela. Bon voici un test avec un message un peu plus long. Bon j'en rajoute pour voir. Ce que j'écris est très original... Bref, je suis un poete Ce que j'écris est très original... Bref, je suis un poete Salut christophe, arrives tu à lire ce message? normalement tu dois lire cela. Bon voici un test avec un message un peu plus long. Bon j'en rajoute pour voir. Ce que j'écris est très original... Bref, je suis un poete Ce que j'écris est très original... Bref, je suis un poete Salut christophe, arrives tu à lire ce message? normalement tu dois lire cela. Bon voici un test avec un message un peu plus long. Bon j'en rajoute pour voir. Ce que j'écris est très original... Bref, je suis un poete voila c'est la fin blablabla:-)"
-
-
- message=message+message+message+message+message+message+message+message
- message=message[0:len(message)/1]
- leng_msg=len(message)
- message=message+((leng_msg+7)/8*8-leng_msg)*" "
- leng_msg=len(message)
-
- leng='%08d'%len(message)
-
-
-
-
- len_leng=len(leng)
- leng_error=int(len_leng)
- leng_cor=leng
- List_pack=a2b_list(leng_cor)
-
- List_random=[]
- while len(List_random)<Size_message:
- X=(X*X)%M
- List_random.extend(Denary2Binary(X))
-
- size=0
- for i in range(leng_msg/8):
- m=message[i*8:(i+1)*8]
- m_cor=m
- m_bin=a2b_list(m_cor)
- size=size+len(m_bin)
- List_pack.extend(m_bin)
-
-
- Support=[getBit(level[l],bit_to_read) for l in List_support]
-
-
- Message=[(int(List_pack[l])^int(List_random[l])) for l in xrange(Size_message)]
-
- print "support",len(List_support)
- print "message",len(Message)
- print "weight",len(Weight)
-
- if Size_message!=0:
- (x_b,Stc_message,H_hat) = stc(Support,Weight,Message)
-
- if Size_message!=0:
- print "pourcentage modif",nbdif(x_b,Stc_message)
- print "taille Stc_message",len(Stc_message)
-
-
-
- l=0
- size_mesg=0
- val_mod=0
- #print LL
-
-
- for l in List_support:
- if(size_mesg<len(Stc_message)):
- level[l]=float64(setBit(level[l],bit_to_read,Stc_message[size_mesg]))
- size_mesg+=1
-
- print 'size mesg',size_mesg
- print 'len message',len(Message),len(List_pack)
-
-
-
- zz3=im.new('L',dd.size)
- zz3.putdata(level)
-
- zz3.save(fileout)
- list_nb_bit.append(filein)
- list_nb_bit.append(Size_message)
-
-
-
-
-
-
-listing = os.listdir(path_cover)
-
-list_nb_bit=[]
-l=0
-
-
-
-
-for infile in listing:
- print "current file is: " + infile, path_stego+infile
- mystego(path_cover+infile,path_stego+infile)
- l+=1
-
This section aims at justifying the lightweight attribute of our approach.
To be more precise, we compare the complexity of our schemes to some of
current state of the art of
-steganographic scheme, namely HUGO~\cite{DBLP:conf/ih/PevnyFB10},
+steganographic schemes, namely HUGO~\cite{DBLP:conf/ih/PevnyFB10},
WOW~\cite{conf/wifs/HolubF12}, and UNIWARD~\cite{HFD14}.
-Each of these scheme starts with the computation of the distortion cost
+Each of these schemes starts with the computation of the distortion cost
for each pixel switch and is later followed by the STC algorithm.
Since this last step is shared by all,
we separately evaluate this complexity.
-In all the rest of this section, we consider a $n \times n$ square image.
+In all the remainder of this section, we consider a $n \times n$ square image.
First of all, HUGO starts with computing the second order SPAM Features.
-This steps is in $\theta(n^2 + 2\times 343^2)$ due to the calculation
+This steps is in $\theta(n^2 + 2\times 343^2)$ due to the computation
of the difference arrays and next of the 686 features (of size 343).
Next for each pixel, the distortion measure is calculated by +1/-1 modifying
its value and computing again the SPAM
What follows details the complexity of the distortion evaluation of the
UNIWARD scheme. This one is based to a convolution product $W$ of two elements
-of size $n$ and is again in $\theta(n^2 \times n^2\ln(n^2))$ and a sum $D$ of
+of size $n$ and is again in $\theta(n^2 \times n^2\ln(n^2))$,
+ and a sum $D$ of
these $W$ which is in $\theta(n^2)$.
This distortion computation step is thus in $\theta(6n^4\ln(n) + n^2)$.
-Our edge selection is based on a Canny Filter. When applied on a
+Our edge selection is based on a Canny filter. When applied on a
$n \times n$ square image, the noise reduction step is in $\theta(5^3 n^2)$.
-Next, let $T$ be the size of the canny mask.
+Next, let $T$ be the size of the Canny mask.
Computing gradients is in $\theta(4Tn^2)$ since derivatives of each direction (vertical or horizontal)
are in $\theta(2Tn^2)$.
Finally, thresholding with hysteresis is in $\theta(n^2)$.
Let us recall too that this drawback
can be fixed by considering the LSB matching (LSBM) subcategory, in which
-the $+1$ or $-1$ is randomly added to the cover pixel's LSB value
+a $+1$ or $-1$ is randomly added to the cover pixel's LSB value
only if this one does not correspond to the secret bit.
%TODO : modifier ceci
By considering well-encrypted hidden messages, the probabilities of increasing or decreasing the value of pixels are equal. Then usual statistical approaches
directional filter. Thus, similarly, the distortion function is
the sum of the differences between these wavelet coefficients
computed from the cover and from the stego images.
-
-
Due to this distortion measures, HUGO, WOW and UNIWARD allow
to embed messages that are $7$ times longer than the former
ones with the same level of
indetectability as LSB matching.
However, this improvement has a larger computation cost, mainly due to
the distortion function
-calculus.
+computation.
There remains a large place between random selection of LSB and feature based modification of pixel values.
Contrarily, we argue that some images should not be taken
as a cover because of the nature of their signals.
Consider for instance a uniformly black image: a very tiny modification of its
-pixels can be easily detectable.
+pixels can be easily detected.
Practically speaking, if Alice would send
a hidden message to Bob, she would never consider
such kind of image and a high embedding rate.
will not be able to obtain the original message content.
Doing so makes our steganographic protocol, to a certain extend, an asymmetric one.
-To sum up, in this research work, well-studied and experimented
+To sum up, well-studied and experimented
techniques of signal processing (adaptive edges detection),
coding theory (syndrome-trellis codes), and cryptography
-(Blum-Goldwasser encryption protocol) are combined
-to compute an efficient steganographic
+(Blum-Goldwasser encryption protocol) are combined in this research work.
+The objective is to compute an efficient steganographic
scheme, whose principal characteristic is to take into
consideration the cover image and to be compatible with small computation resources.
The higher it is, the larger the message length that can be inserted is.
Practically, a set of edge pixels is computed according to the
Canny algorithm with parameters $b=7$ and $T=3$.
-The message length is thus defined to be less than
+The message length is thus defined to be lesser than
half of this set cardinality.
If $x$ is too short for $m$, the message is split into sufficient parts
and a new cover image should be used for the remaining part of the message.
Practically, the Canny algorithm generates
a set of edge pixels related to increasing values of $T$ and
until its cardinality
-is sufficient. Even in this situation, our scheme is adapting
+is sufficient. Even in this situation, our scheme adapts
its algorithm to meet all the user's requirements.
Once the map of possibly modified pixels is computed,
two methods may further be applied to extract bits that
-are really modified.
+are really changed.
The first one randomly chooses the subset of pixels to modify by
applying the BBS PRNG again. This method is further denoted as a \emph{sample}.
Once this set is selected, a classical LSB replacement is applied to embed the
% the fuzzy logic edge detector.
For a given set of parameters,
-the canny algorithm returns a numerical value and
+the Canny algorithm returns a numerical value and
states whether a given pixel is an edge or not.
In this article, in the Adaptive strategy
we consider that all the edge pixels that
since there exists a reverse function for all its steps.
More precisely, let $b$ be the most significant bits and
-$T$ be the size of the canny mask, both be given as a key.
+$T$ be the size of the Canny mask, both be given as a key.
Thus, the same edge detection is applied on a stego content $Y$ to
produce the sequence $y$ of LSBs.
If the STC approach has been selected in embedding, the STC reverse
150 & \textrm{if} & \vert X_{ij} - Y_{ij} \vert = 2 \\
225 & \textrm{if} & \vert X_{ij} - Y_{ij} \vert = 3
\end{array}
-\right..
+\right.
$$
This function allows to emphasize differences between contents.
Notice that since $b$ is 7 in Fig.~\ref{fig:diff7}, the embedding is binary
Let us explain this embedding on a small illustrative example where
$m$ and $x$ are respectively a 3 bits column
-vector and a 7 bits column vector and where
+vector and a 7 bits column vector, and where
$\rho_X(i,x,y)$ is equal to 1 for any $i$, $x$, $y$
-(\textit{i.e.}, $\rho_X(i,x,y) = 0$ if $x = y$ and $0$ otherwise).
+(\textit{i.e.}, $\rho_X(i,x,y) = 0$ if $x = y$ and $1$ otherwise).
Let $H$ be the binary Hamming matrix
$$
In the general case, communicating a message of $p$ bits in a cover of
$n=2^p-1$ pixels needs $1-1/2^p$ average changes.
-This Hamming embeding is really efficient to very small payload and is
-not well suited when the size of the message is larger, as in real situation.
+This Hamming embedding is really efficient to very small payload and is
+not well suited when the size of the message is larger, as in real situations.
The matrix $H$ should be changed to deal with higher payload.
Moreover, for any given $H$, finding $y$ that solves $Hy=m$ and
that minimizes $D_X(x,y)$, has an exponential complexity with respect to $n$.