Учитывая пожелания читателей и статистику посещаемости для сообщений, этот пост посвящается практической реализации одного из методов стегоанализа (стеганоанализа, steganalysis). Ранее уже приводилось теоретическое обоснование различия гистограмм яркостей цветовых компонент для пустого изображения-контейнера и заполненного стегоизображения.
В русскоязычном интернете невозможно найти хоть какую-нибудь работающую программу для стегоанализа. Однако, теоретические и практические (коммерческие) разработки в мире шагнули весьма далеко.
Рис. 1 Гистограмма пустого и заполненного изображений |
Не будем отставать и создадим наш собственный скрипт для Matlab, который будет отыскивать последовательное вложение. (Встроить вложение можно, с помощью ранее описанного метода). Метод обнаружения последовательного встраивания будем разрабатывать для 24 битного BMP изображения.
По приведенной ранее классификации, описываемый метод стегоанализа относится к
вероятностным методам,
которые в пространственной форме представления изображения
с помощью статистического критерия Хи квадрат ищут стеганографические вложения,
сделанные определенным алгоритмом.
Кто не понял предыдущее предложение - не переживайте: я сам его до конца не понимаю, а стереть жалко.
сделанные определенным алгоритмом.
Кто не понял предыдущее предложение - не переживайте: я сам его до конца не понимаю, а стереть жалко.
Общее описание алгоритма:
1. Разбиваем изображение на цветовые компоненты.
2. Каждую цветовую компоненту разбиваем на непересекающиеся прямоугольные блоки достаточной величины (Что такое «достаточная величина» требует особого исследования).
3. Для каждого блока строим эмпирическую гистограмму яркости. (Эмпирический – основанный на опыте, изучении фактов, опирающийся на непосредственное наблюдение, эксперимент.) На рисунке 1 гистограмма обозначена синим цветом.
4. Для каждого блока строим теоретическую гистограмму на основе эмпирической. Для построения теоретической гистограммы найдем среднее арифметическое количества пикселей с соседними яркостями.
Соседними будут яркости 0<->1 2<->3 … 254<->255, или в двоичной системе исчисления:
0000 0000<->0000 0001;
0000 0010<->0000 0011;
...
1111 1110<->1111 1111.
Теоретическая гистограмма наблюдается при встраивании данных в каждый бит (пиксель) цветовой компоненты. На рисунке 1 - обозначена красным цветом. Можно сказать, что при встраивании количество пикселей в соседних парах распределено равновероятно.
5. Для каждого блока сравним схожесть теоретической и эмпирической гистограмм с помощью статистики Хи квадрат (Пирсона). Если теоретическая и эмпирическая гистограммы различаются несущественно, то вероятно, что в каждый пиксель цветовой компоненты исследуемого блока встроена скрытая информация. Вычисляем значение статистики для проверяемого блока цветовой компоненты:
Теоретическая и эмпирическая гистограммы считаются схожими, если полученное эмпирическое значение статистики Хи квадрат меньше теоретического значения статистики Хи квадрат при заданном уровне значимости а и количестве степеней свободы k-1.
Если данное неравенство справедливо, то мы обнаружили встраивание в проверяемый блок. Однако, хватит уже теории.
Matlab cкрипт для гистограммного статистического стегоанализа
Данный скрипт является функцией, которую можно вызвать из командной строки MATLAB.
На вход функции подаются: адрес анализируемого изображения, размер непересекающихся прямоугольных блоков по горизонтали и вертикали, уровень значимости а (рекомендуется 0.9).
На выходе получаем изображения трех цветовых компонент: RED_out, GREEN_out, BLUE_out.
Серым цветом показаны места, где соседние пары яркостей имеют равновероятное распределение, т.е. предполагается встраивание. Красным, зеленым и синим цветом, соответственно, обозначены места цветовых компонент, где встраивания нет.
function [RED_out,GREEN_out,BLUE_out] = histo_chi2_steganalysis(IMG_in,stepX,stepY,Prbb);
% pirson_Xi_2_Analiz
Picture = imread(IMG_in,'bmp');
Red = Picture(:,:,1);
Green = Picture(:,:,2);
Blue = Picture(:,:,3);
[Pheight,Pwidth] = size(Red);
a_ind_X = 1:stepX:Pwidth;
a_ind_Y = 1:stepY:Pheight;
countX = size(a_ind_X,2);
countY = size(a_ind_Y,2);
Добавляем к изображению широкую «границу» из пикселей, чтобы крайние блоки не были обрезаны границей изображения. brdrd_Red = [Red;Red((countY-1)*stepY:-1:(countY-2)*stepY+1,:)];
brdrd_Red = [brdrd_Red,brdrd_Red(:,(countX-1)*stepX:-1:(countX-2)*stepX+1)];
brdrd_Green = [Green; Green((countY-1)*stepY:-1:(countY-2)*stepY+1,:)];
brdrd_Green = [brdrd_Green, brdrd_Green(:,(countX-1)*stepX:-1:(countX-2)*stepX+1)];
brdrd_Blue = [Blue;Blue((countY-1)*stepY:-1:(countY-2)*stepY+1,:)];
brdrd_Blue = [brdrd_Blue,brdrd_Blue(:,(countX-1)*stepX:-1:(countX-2)*stepX+1)];
Формируем изображение с добавленными границами.
brdrd_Picture(:,:,1) = brdrd_Red(:,:);
brdrd_Picture(:,:,2) = brdrd_Green(:,:);
brdrd_Picture(:,:,3) = brdrd_Blue(:,:);
Зададим размеры массивов для хранения гистограммы, наблюдаемого значения Хи квадрат - ArrayReal и теоретического значения Хи квадрат - ArrayTeor:
HistoTeor=zeros(1,256);
ArrayReal = zeros(size(a_ind_Y,2),size(a_ind_X,2));
ArrayTeor = zeros(size(a_ind_Y,2),size(a_ind_X,2));
В цикле будем обращаться последовательно к первой, второй и третьей цветовой компонентам.
for Z = 1:3
IMG = brdrd_Picture(:,:,Z);
Для каждой цветовой компоненты последовательно переберем все, исследуемые на предмет встраивания, блоки. Для каждого блока определим эмпирическое и теоретическое значения Хи квадрат (процесс достаточно подробно прокомментирован в самом коде).
for Y = 1:stepY:Pheight
for X = 1:stepX:Pwidth
areaXY = IMG(Y:Y+stepY,X:X+stepX);
% POSTROENIE EMPIRICHESKOI GISTOGRAMMY
% REZUL'TAT - VERTIKAL'NYI VEKTOR #HistoEmpir#
HistoEmpir = imhist(areaXY);
% TRANSPONIROVANIE VEKTORA #HistoEmpir#
% REZUL'TAT - GORIZONTAL'NYI VEKTOR #HistoEmpir#
HistoEmpir = transpose(HistoEmpir);
% POSTROENIE TEORETIChESKOI GISTOGRAMMY #HistoTeor#
% REZUL'TAT - GORIZONTAL'NYI VEKTOR #HistoTeor#
k = 1:2:256;
HistoTeor(k) = (HistoEmpir(k)+HistoEmpir(k+1))/2;
HistoTeor(k+1) = (HistoEmpir(k)+HistoEmpir(k+1))/2;
%*******************************************************************
% RASChET VEROYaTNOSTEI EMPIRICHESKOI i TEORETIChESKOI YaRKOSTEI #VarTeor# #VarEmpir#
% REZUL'TAT - GORIZONTAL'NYE VEKTORA #VarEmpir# #VarTeor#
VarEmpir = HistoEmpir;
VarTeor = HistoTeor;
zero_ind = find(VarTeor <=20);
VarEmpir(zero_ind) = [];
VarTeor(zero_ind) = [];
% RASChET MASSIVA-SYR'Ya DLYa RASChETA REAL'NOGO ZNAChENIYa #Xi2#
% REZUL'TAT - GORIZONTAL'NYI VEKTOR #Xi2#
Xi2 = ((VarEmpir-VarTeor).^2)./VarTeor;
% UDALENIE OShIBOChNYH ZNAChENII DELENIYa NA NOL' IZ #Xi2#
Xi2 = Xi2(~isnan(Xi2));
% RASChET REAL'NOGO ZNAChENIYa #Xi2#
Xi2Real = sum(Xi2);
% RASChET TABLIChNOGO ZNAChENIYa #Xi2#
Xi2Teor = chi2inv(Prbb,size(Xi2,2)-1);
% FORMIROVANIE NAGLYaDNYH MASSIVOV REAL'NOGO I TABLIChNOGO ZNAChENII #Xi2#
ArrayReal((Y-1)/stepY+1,(X-1)/stepX+1) = Xi2Real;
ArrayTeor((Y-1)/stepY+1,(X-1)/stepX+1) = Xi2Teor;
end;
end;
Результаты расчетов статистик Хи квадрат занесем в соответствующие массивы для первой, второй и третьей цветовых компонент. Массивы ArrayCompare хранят логические значения для каждой из анализируемых областей: «1» - встраивание есть, «0» - встраивания нет.
if (Z == 1)
RED_ArrayReal = ArrayReal;
RED_ArrayTeor = ArrayTeor;
RED_ArrayCompare = uint8(RED_ArrayReal
end;
if (Z == 2)
GREEN_ArrayReal = ArrayReal;
GREEN_ArrayTeor = ArrayTeor;
GREEN_ArrayCompare = uint8(GREEN_ArrayReal
end;
if (Z == 3)
BLUE_ArrayReal = ArrayReal./ArrayTeor;
BLUE_ArrayTeor = ArrayTeor./ArrayTeor;
BLUE_ArrayCompare = uint8(BLUE_ArrayReal
end;
end;
На данном этапе у нас уже есть информация о «загрязненности» блоков изображения встраиванием. Для удобства пользователя покажем данные блоки на изображении.
В цикле перебираются все анализируемые блоки для каждой компоненты. Если анализируемый блок чистый, выводим его «родным» (красным, зеленым или синим) для компоненты цветом. Если блок со встраиванием, выводим его серым цветом
for Y = 1:stepY:Pheight
for X = 1:stepX:Pwidth
RED_out(Y:Y+stepY-1,X:X+stepX-1,1) = brdrd_Red(Y:Y+stepY-1,X:X+stepX-1);
RED_out(Y:Y+stepY-1,X:X+stepX-1,2) = brdrd_Red(Y:Y+stepY-1,X:X+stepX-1).*RED_ArrayCompare((Y-1)/stepY+1,(X-1)/stepX+1);
RED_out(Y:Y+stepY-1,X:X+stepX-1,3) = brdrd_Red(Y:Y+stepY-1,X:X+stepX-1).*RED_ArrayCompare((Y-1)/stepY+1,(X-1)/stepX+1);
GREEN_out(Y:Y+stepY-1,X:X+stepX-1,1) = brdrd_Green(Y:Y+stepY-1,X:X+stepX-1).*GREEN_ArrayCompare((Y-1)/stepY+1,(X-1)/stepX+1);
GREEN_out(Y:Y+stepY-1,X:X+stepX-1,2) = brdrd_Green(Y:Y+stepY-1,X:X+stepX-1);
GREEN_out(Y:Y+stepY-1,X:X+stepX-1,3) = brdrd_Green(Y:Y+stepY-1,X:X+stepX-1).*GREEN_ArrayCompare((Y-1)/stepY+1,(X-1)/stepX+1);
BLUE_out(Y:Y+stepY-1,X:X+stepX-1,1) = brdrd_Blue(Y:Y+stepY-1,X:X+stepX-1).*BLUE_ArrayCompare((Y-1)/stepY+1,(X-1)/stepX+1);
BLUE_out(Y:Y+stepY-1,X:X+stepX-1,2) = brdrd_Blue(Y:Y+stepY-1,X:X+stepX-1).*BLUE_ArrayCompare((Y-1)/stepY+1,(X-1)/stepX+1);
BLUE_out(Y:Y+stepY-1,X:X+stepX-1,3) = brdrd_Blue(Y:Y+stepY-1,X:X+stepX-1);
end;
end;
Избавляемся от широкой границы, добавленной для работы с крайними блоками.
RED_out = RED_out(1:Pheight,1:Pwidth,:);
GREEN_out = GREEN_out(1:Pheight,1:Pwidth,:);
BLUE_out = BLUE_out(1:Pheight,1:Pwidth,:);
На данном этапе функция уже сформировала переменные-изображения, на которых видны результаты анализа. Для удобства добавим вывод результатов на экран. По желанию следующие три строки можно закомментировать или удалить.
figure;imagesc(RED_out);
figure;imagesc(GREEN_out);
figure;imagesc(BLUE_out);
end
Практическое использование функции для стегоанализа последовательного вложения
Кратко посмотрим, как работает наша функция.
Для анализа возьмем изображение 'stego_murzik3.bmp', ширину и высоту блока возьмем в четверть размера изображения, уровень значимости зададим 0.8:
[RED_out,GREEN_out,BLUE_out] = histo_chi2_steganalysis('stego_murzik3.bmp',512,512,0.8);
В результате получаем следующие изображения:
Красная компонента вся отображается серым цветом, что означает полное встраивание в красную компоненту. Зеленая компонента – зелена лишь наполовину, что проявляет области со встраиванием (серая) и без встраивания (зеленая). Синяя компонента показывает отсутствие встраивания по всей площади.
Кажется все замечательно. Однако попробуем уменьшить размер блоков, на которые изображение разбивается для анализа. Используем блоки размером 200х200 пикселей:
[RED_out,GREEN_out,BLUE_out] = histo_chi2_steganalysis('stego_murzik3.bmp',200,200,0.8);
Как видим, в местах определенных предыдущим анализом как чистые от встраивания оно "появилось". Это говорит о важности выбора размера и формы блоков, на которые разбивается для анализа изображение.
Результат прохода узкими вертикальными полосками 30х1023:
[RED_out,GREEN_out,BLUE_out] = histo_chi2_steganalysis('stego_murzik3.bmp',30,1023,0.8);
Анализ квадратиками 30х30:
[RED_out,GREEN_out,BLUE_out] = histo_chi2_steganalysis('stego_murzik3.bmp',30,30,0.8);
Все желающие могут скачать данную функцию и изображения, на которых можно самостоятельно посмотреть, как она работает.
Полезная статья, спасибо!
ОтветитьУдалитьПожалуйста, рад помочь.
ОтветитьУдалитьЕсли еще будут какие-то вопросы - спрашивайте.
Спасибо! очень интересная статья!
ОтветитьУдалитьно у меня возник вопрос о том как бы извлечь тот самый том "войны и мир", так сказать демодулировать изображение. возможно ли это вообще? был бы очень признателен.
В более ранних постах можно посмотреть описание и скрипты для сокрытия данных в НЗБ:
ОтветитьУдалитьhttp://gr1g0ry.blogspot.com/2011/03/steganography-in-matlab.html
и для извлечения скрытых данных:
http://gr1g0ry.blogspot.com/2011/03/steganography-in-matlab-extracting.html
Здравствуйте!
ОтветитьУдалитьРешил протестировать Ваш скрипт. При запуске выдает:
??? Input argument "IMG_in" is undefined.
Error in ==> histo_chi2_steganalysis at 5
Picture = imread(IMG_in,'bmp');
Файл IMG_in.bmp находится в одной папке с файлом скрипта. Подскажите в чем проблема?
Спасибо!
Добрий день! потрібна ваша допомого, я попробував скачати скріпт проте ссилка на даний час застаріла! Якщо у вас залишились матеріали по даній темі буду вдячний якщо скинете на пошту: Black7moke@gmail.com
УдалитьДякую
Данный пример, в отличие от предыдущих, написан в виде функции для Matlab. Поэтому его нужно запускать из командной строки.
ОтветитьУдалитьНапример:
>>[RED_out,GREEN_out,BLUE_out] = histo_chi2_steganalysis('stego_murzik3.bmp',512,512,0.8);
Надеюсь ответ актуален.
Заработало.=) Спасибо за ответ!
ОтветитьУдалитьЗдравстуйте!
ОтветитьУдалитьПодскажите, пожалуйста, что нужно указывать при использовании материалов с Вашего сайта?
Спасибо.
Если Вы пишете курсовую или диплом, наверное лучше будет сослаться на мои статьи в печатных изданиях, например:
ОтветитьУдалитьhttp://www.nbuv.gov.ua/portal/Soc_Gum/VSUNU/2007_5_1/15.pdf
или
http://www.google.com.ua/search?hl=ru&client=opera&rls=ru&channel=suggest&biw=1020&bih=635&q=%D0%A1%D1%82%D0%B0%D1%82%D0%B8%D1%81%D1%82%D0%B8%D1%87%D0%BD%D0%B8%D0%B9+%D0%BC%D0%B5%D1%82%D0%BE%D0%B4+%D1%81%D1%82%D0%B5%D0%B3%D0%B0%D0%BD%D0%BE%D0%B0%D0%BD%D0%B0%D0%BB%D1%96%D0%B7%D1%83&aq=f&aqi=&aql=&oq=
Если собираетесь публиковать что либо в интернете, пожалуйста поставьте ссылку на этот сайт.
Благодарю, Григорий. Занимательная тема.
ОтветитьУдалитьПосле прочтения книги "Цифровая Стеганография" тоже увлекся (правда писать приходится на VBA ;)).
Представленные ранее методы, они хоть и простые, но абсолютно не устойчивые к обработке. Будут ли вашем блоге рассматриваться более робастные (устойчивые) алгоритмы?
Спасибо за вопрос.
ОтветитьУдалитьДа я действительно хочу сделать посты о внедрении скрытых данных в JPEG и JPEG2000. Сейчас есть заделы на пост про встраивание в НЗБ рассеяно по площади всего изображения.(Что немного более устойчиво к стегоанализу, но все так же неустойчиво к удалению сокрытой информации.)
перезалейте скрипт !!!
ОтветитьУдалитьДа если можно перезалейте скрипт
ОтветитьУдалитьСпасибо большое за ваши статьи. Очень интересно вас читать. Совмещаю приятное с полезным, так сказать. Если вам не трудно, пришлите, пожалуйста, скрипт на lisfo4ka@gmail.com. Буду очень, очень признательна :)
ОтветитьУдалитьБольшая просьба подправить статью.
ОтветитьУдалитьВыражения для определения массива BLUE_ArrayCompare "обрезаны" на самом интересном: RED_ArrayCompare = uint8(RED_ArrayReal
Для других цветов так же.
Здравствуйте! У меня такой вопрос где можно скачать данную программу! Спасибо
ОтветитьУдалить