“程序设计与算法训练”课程设计“二值图像数字水印技术的实践”

  某垃圾大学数据结果课程设计(题目抄袭自某牛逼985高校)。

  github项目地址(含报告):https://github.com/25thengineer/Data-Structure-Course-Design-Practice-of-Binary-Image-Digital-Watermarking-Technology

  (1)操作系统:Ubuntu 16.04 LTS;

  (2)开发工具:Qt、Qt Creator 5.12.0; 

  (3)实现语言:C++

  源代码:

 1 #ifndef ADDDITIONAL_UTILITY_H
 2 #define ADDDITIONAL_UTILITY_H
 3 
 4 #include<sys/types.h>
 5 #include<iostream>
 6 #include<fstream>
 7 #include<QtCore>
 8 #include<QMessageBox>
 9 #include<stdio.h>
10 #include<string.h>
11 #pragma pack(2)// In the Linux environment
12 
13 
14 using byteArray = QVector<bool>;
15 
16 //******************************************top******************************************************
17 //In the Linux environment
18 typedef struct BITMAPFILEHEADER
19 {
20     u_int16_t bfType;
21     u_int32_t bfSize;
22     u_int16_t bfReserved1;
23     u_int16_t bfReserved2;
24     u_int32_t bfOffBits;
25 }BITMAPFILEHEADER;
26 typedef struct BITMAPINFOHEADER
27 {
28     u_int32_t biSize;
29     u_int32_t biWidth;
30     u_int32_t biHeight;
31     u_int16_t biPlanes;
32     u_int16_t biBitCount;
33     u_int32_t biCompression;
34     u_int32_t biSizeImage;
35     u_int32_t biXPelsPerMeter;
36     u_int32_t biYPelsPerMeter;
37     u_int32_t biClrUsed;
38     u_int32_t biClrImportant;
39     struct BITMAPINFOHEADER &operator=( struct BITMAPINFOHEADER &BMIH )
40     {
41         biSize = BMIH.biSize;
42         biWidth = BMIH.biWidth;
43         biHeight = BMIH.biHeight;
44         biPlanes = BMIH.biPlanes;
45         biClrUsed = BMIH.biClrUsed;
46         biSizeImage = BMIH.biSizeImage;
47         biCompression = BMIH.biCompression;
48         biClrImportant = BMIH.biClrImportant;
49         biXPelsPerMeter = BMIH.biXPelsPerMeter;
50         biYPelsPerMeter = BMIH.biYPelsPerMeter;
51         //qDebug() << "214235423" << endl;
52         return *this;
53     }
54 
55 }BITMAPINFODEADER;
56 
57 typedef unsigned char BYTE;
58 typedef unsigned short WORD;
59 typedef unsigned int DWORD;
60 typedef long LONG;
61 
62 typedef struct tagRGBQUAD
63 {
64     BYTE rgbBlue;
65     BYTE rgbGreen;
66     BYTE rgbRed;
67     BYTE rgbReserved;
68 }RGBQUAD;
69 
70 
71 typedef struct tagIMAGEDATA
72 {
73     BYTE blue;
74     BYTE green;//canceled the annotation by DFZ
75     BYTE red;//canceled the annotation by DFZ
76 }IMAGEDATA;
77 
78 
79 //********************************************bottom*******************************************
80 
81 #endif // ADDDITIONAL_UTILITY_H
#ifndef BMPUTIL_H
#define BMPUTIL_H

#include "addditional_utility.h"

class watermark
{
public:
    QString array2byte(byteArray &array);
    QString array2str(byteArray &array);
    byteArray byte2Array(QString &number);
    byteArray decodeImg(uchar* buffer, uchar* dst, const int width, const int height, const int length);
    uchar* edgeExtract(uchar* buffer, const int width, const int height);
    byteArray encode(byteArray src, byteArray key);
    byteArray generateKey(const int length);
    byteArray img2Array(QString &dir);
    uchar* readBmp(const char *bmpName, int& bmpWidth, int& bmpHeight);
    byteArray str2Array(QString &str);
    uchar* substract(uchar* buffer1, uchar* buffer2, const int size);
    uchar* translation(uchar* buffer, const int width, const int height, int x_off, int y_off);
    uchar* watermarkImg(uchar* buffer, uchar* edge, const int size, byteArray code);
    bool savebmp(const char* filename, uchar* buffer, const u_int32_t height, const u_int32_t width);
private:
    BITMAPINFODEADER BMIH;
    BITMAPFILEHEADER BMFH;
    int biWidth;
    int biHeight;
    int biBitCount;
    int lineByte;
    RGBQUAD* pColorTable;
protected:


};

#endif // BMPUTIL_H
 1 #ifndef MAINWINDOW_H
 2 #define MAINWINDOW_H
 3 
 4 #include <QMainWindow>
 5 #include <QPixmap>
 6 
 7 namespace Ui
 8 {
 9 class MainWindow;
10 }
11 
12 using byteArray = QVector<bool>;
13 
14 class MainWindow : public QMainWindow
15 {
16     Q_OBJECT
17 public:
18     explicit MainWindow(QWidget *parent = 0);
19     ~MainWindow();
20 
21 private slots:
22     void on_pushButtonBrowse_clicked();
23     void on_lineEdit_textChanged(const QString &arg1);
24     void on_pushButtonEncode_clicked();
25     void on_pushButtonDecode_clicked();
26 
27 private:
28     Ui::MainWindow *ui;
29     QPixmap image;
30 
31     byteArray key;
32     uchar* dst;
33 };
34 
35 #endif // MAINWINDOW_H
1 #include "addditional_utility.h"
  1 #include "bmputil.h"
  2 
  3 uchar* watermark::readBmp(const char *bmpName, int& bmpWidth, int& bmpHeight)
  4 {
  5     FILE *fp = fopen(bmpName, "rb");
  6     if(fp == Q_NULLPTR)
  7     {
  8         QMessageBox::warning(Q_NULLPTR, "Error", "Error in Open File!");
  9         return Q_NULLPTR;
 10     }
 11 
 12     // skip the fileheader
 13     fseek(fp, sizeof(BITMAPFILEHEADER), SEEK_CUR);
 14 
 15     // read the infoheader
 16     //BITMAPINFOHEADER* head = new BITMAPINFOHEADER;
 17     watermark WT;
 18     //infohead = &(WT.BMIH);
 19     BITMAPINFODEADER infohead = WT.BMIH;
 20     fread(&infohead,sizeof(BITMAPINFOHEADER),1,fp);
 21     //fread(infoHead, sizeof(BITMAPINFOHEADER), 1, fp);
 22     bmpWidth = infohead.biWidth;
 23     bmpHeight = infohead.biHeight;
 24     biBitCount = infohead.biBitCount;
 25     lineByte = (bmpWidth*biBitCount/8+3)/4*4;
 26     //qDebug() << infohead.biSize << endl;
 27     //qDebug() << infohead.biWidth << endl;
 28     //qDebug() << infohead.biHeight << endl;
 29     //qDebug() << infohead.biBitCount << endl;
 30     if (biBitCount == 8)
 31     {
 32         pColorTable = new RGBQUAD[256];
 33         fread(pColorTable, sizeof(RGBQUAD), 256, fp);
 34 
 35         uchar* pBmpBuf = new uchar[ bmpWidth * bmpHeight ];
 36         fread(pBmpBuf, sizeof(uchar), bmpWidth * bmpHeight, fp);
 37         fclose(fp);
 38 
 39         uchar* buffer = new uchar[bmpWidth * bmpHeight];
 40         for(int i = 0; i < bmpHeight; i++)
 41         {
 42             for(int j = 0; j<bmpWidth; j++)
 43             {
 44                 if(pBmpBuf[(bmpHeight- i - 1)*bmpWidth + j] != 255 && pBmpBuf[(bmpHeight- i - 1)*bmpWidth + j] != 0)
 45                 {
 46                     QMessageBox::warning(Q_NULLPTR, "Error", "This is not a binary image!");
 47                     return Q_NULLPTR;
 48                 }
 49                 buffer[i*bmpWidth + j] = pBmpBuf[(bmpHeight- i - 1)*bmpWidth + j];
 50             }
 51         }
 52         return buffer;
 53     }
 54     else
 55     {
 56         QMessageBox::warning(Q_NULLPTR, "Error", "Our program can only deal with 8-bit image!");
 57         return Q_NULLPTR;
 58     }
 59 }
 60 
 61 bool watermark::savebmp(const char* filename, uchar* buffer, const u_int32_t height, const u_int32_t width)
 62 {
 63     //RGBQUAD *pColorTable = new RGBQUAD;
 64     if(buffer == Q_NULLPTR)
 65     {
 66         QMessageBox::warning(Q_NULLPTR, "Error", "The Buffer is nullptr!");
 67         return false;
 68     }
 69     uchar* data = new uchar[height*width];
 70     for(int i = 0; i < height; i++)
 71     {
 72         for(int j = 0; j<width; j++)
 73         {
 74             data[i*width + j] = buffer[(height- i - 1)*width + j];
 75         }
 76     }
 77 
 78     int colorTableSize = 1024;
 79     BITMAPFILEHEADER fileHeader;
 80     fileHeader.bfType = 0x4D42;
 81     fileHeader.bfReserved1 = 0;
 82     fileHeader.bfReserved2 = 0;
 83     fileHeader.bfSize = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + colorTableSize + height*width;
 84     fileHeader.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + colorTableSize;
 85 
 86     BITMAPINFOHEADER bitmapHeader = { 0 };
 87     bitmapHeader.biSize = sizeof(BITMAPINFOHEADER);
 88     //qDebug() << "In bool watermark::savebmp(const char* filename, uchar* buffer, const u_int32_t height, const u_int32_t width), height = " << height << endl;
 89     //qDebug() << "In bool watermark::savebmp(const char* filename, uchar* buffer, const u_int32_t height, const u_int32_t width), width = " << width << endl;
 90     //qDebug() << sizeof(BITMAPINFOHEADER) << endl;
 91     bitmapHeader.biHeight = height;
 92     bitmapHeader.biWidth = width;
 93     bitmapHeader.biPlanes = 1;
 94     bitmapHeader.biBitCount = 8;
 95     bitmapHeader.biSizeImage = height*width;
 96     bitmapHeader.biCompression = 0;
 97 
 98     FILE *fp = fopen(filename, "wb");
 99     //qDebug() << "OK! line 154 " << endl;
100     if(fp == Q_NULLPTR)
101     {
102         QMessageBox::warning(Q_NULLPTR, "Error", "Error in Save File!");
103         //qDebug() << "OK! line 156 " << endl;
104         return false;
105     }
106     else
107     {
108         fwrite(&fileHeader, sizeof(BITMAPFILEHEADER), 1, fp);
109         //qDebug() << "OK! line 162 " << endl;
110         fwrite(&bitmapHeader, sizeof(BITMAPINFOHEADER), 1, fp);
111         //qDebug() << "OK! line 164 " << endl;
112         //qDebug() << "pColorTable address = " << pColorTable << endl;
113         fwrite(pColorTable, sizeof(RGBQUAD), 256, fp);
114         delete pColorTable;
115         //qDebug() << "OK! line 168 " << endl;
116         fwrite(data, height*width, 1, fp);
117         delete []data;
118         //qDebug() << "OK! line 171 " << endl;
119         fclose(fp);
120         //qDebug() << "OK! line 173 " << endl;
121         return true;
122     }
123 }
124 
125 
126 // generate keyArray
127 byteArray watermark::generateKey(const int length)
128 {
129     byteArray res;
130     for(int i = 0; i<length; i++)
131     {
132         if(double(qrand())/RAND_MAX > 0.5)
133         {
134             res.append(true);
135         }
136         else
137         {
138             res.append(false);
139         }
140     }
141 
142     return res;
143 }
144 
145 //获得原buffer图像右移x_off个单位,下移y_off个单位后得到的图像
146 uchar* watermark::translation(uchar* buffer, const int width, const int height, int x_off, int y_off)
147 {
148     uchar* res = new uchar[width*height];
149     for(int i = 0; i<height; i++)
150     {
151         for(int j = 0;j<width; j++)
152         {
153             if(i-x_off < 0 || j-y_off < 0)
154             {
155                 res[i*width + j] = 0;
156             }
157             else
158             {
159                 res[i*width + j] = buffer[(i - x_off)*width + (j - y_off)];
160             }
161         }
162     }
163 
164     return res;
165 }
166 
167 // 获得buffer1和buffer2相减得到的结果
168 uchar* watermark::substract(uchar* buffer1, uchar* buffer2, const int size)
169 {
170     uchar* res = new uchar[size];
171     for(int i = 0; i<size; i++)
172     {
173         res[i] = buffer1[i] > buffer2[i] ? buffer1[i] - buffer2[i] : 0;
174     }
175     return res;
176 }
177 
178 // 获得从buffer提取到的边缘图像,用作添加水印位置的参考
179 uchar* watermark::edgeExtract(uchar* buffer, const int width, const int height)
180 {
181     uchar* BL = substract(translation(buffer, width, height, 1, 0), buffer, width*height);
182     uchar* BR = substract(translation(buffer, width, height, -1, 0), buffer, width*height);
183     uchar* BT = substract(translation(buffer, width, height, 0, 1), buffer, width*height);
184     uchar* BB = substract(translation(buffer, width, height, 0, -1), buffer, width*height);
185 
186     uchar* B1 = new uchar[height*width];
187     for(int i = 0; i<height*width; i++)
188     {
189         BL[i] = BL[i]/255;
190         BR[i] = BR[i]/255;
191         BT[i] = BT[i]/255;
192         BB[i] = BB[i]/255;
193 
194         int lr = BL[i] + BR[i];
195         int tb = BT[i] + BB[i];
196         int b = lr + tb;
197 
198         B1[i] = 0;
199         if((b == 1) ||(b == 2 && lr != 2 && tb != 2))
200         {
201             B1[i] = 1;
202         }
203     }
204 
205     uchar* res = new uchar[height*width];
206     for(int i = 0; i<height; i++)
207     {
208         for(int j = 0; j<width; j++)
209         {
210             res[i*width + j] = B1[i*width + j] * 255;
211             if(B1[i*width + j])
212             {
213                 int sum1 = 0, sum2 = 0;
214                 for(int a = -1; a<2; a++)
215                 {
216                     if(a + i <0 || a+ i >= height)
217                     {
218                         continue;
219                     }
220                     for(int b = -1; b<2; b++)
221                     {
222                         if(b +j <0 || b+j>=width)
223                         {
224                             continue;
225                         }
226                         sum1 += buffer[(a + i) *width + (b + j)]/255;
227                         sum2 += B1[(a + i) *width + (b + j)];
228                     }
229                 }
230                 if(sum1 == sum2)
231                 {
232                     res[i*width + j] = 0;
233                 }
234             }
235         }
236     }
237 
238     return res;
239 }
240 
241 // 由边缘图像和原图获得水印编码后的图像
242 uchar* watermark::watermarkImg(uchar* buffer, uchar* edge, const int size, byteArray code)
243 {
244     uchar* res = new uchar[size];
245     for(int i = 0; i<size; i++)
246     {
247         res[i] = buffer[i];
248     }
249     int count = 0;
250     for(int i = 0; i<size; i++)
251     {
252         if(edge[i]==255)
253         {
254             res[i] = 255*code[count++];
255             if(count == code.length())
256             {
257                 return res;
258             }
259         }
260     }
261     QMessageBox::warning(Q_NULLPTR, "Error", "The image is too small to contain such a code!");
262     return Q_NULLPTR;
263 }
264 
265 byteArray watermark::decodeImg(uchar* buffer, uchar* dst, const int width, const int height, const int length)
266 {
267     uchar* edge = edgeExtract(buffer, width, height);
268     byteArray res;
269     for(int i = 0; i<width*height; i++)
270     {
271         if(edge[i] == 255)
272         {
273             res.append(dst[i]);
274             if(length == res.length())
275             {
276                 return res;
277             }
278         }
279     }
280     QMessageBox::warning(Q_NULLPTR, "Error", "The image is too small to contain such a code!");
281     return byteArray();
282 }
283 
284 byteArray watermark::byte2Array(QString &number)
285 {
286     byteArray res;
287     for(auto byte : number)
288     {
289         if(byte == '1')
290         {
291             res.append(true);
292         }
293         else if(byte == '0')
294         {
295             res.append(false);
296         }
297         else
298         {
299             QMessageBox::warning(nullptr, "Error", "Error in byte2Array: Charater else than 0 and 1!\nThe application will be forced to abort.");
300             throw EXIT_FAILURE;
301         }
302     }
303     return res;
304 }
305 
306 byteArray watermark::str2Array(QString &str)
307 {
308     QString num;
309     for(auto character : str)
310     {
311         int i = character.unicode();
312         QString ele = QString::number(i, 2);
313         for(int j = 0;j<8-ele.length();j++)
314         {
315             num += '0';
316         }
317         num += QString::number(i, 2);
318     }
319     qDebug()<<num;
320     return byte2Array(num);
321 }
322 
323 byteArray watermark::img2Array(QString &dir)
324 {
325     Q_UNUSED(dir);
326     QString str = "01010101010101010101010101010101";
327     //return byte2Array(QString("01010101010101010101010101010101"));
328     return byte2Array(str);
329 }
330 
331 QString watermark::array2byte(byteArray &array)
332 {
333     QString res;
334     for(auto ele:array)
335     {
336         if(ele)
337         {
338             res.append('1');
339         }
340         else
341         {
342             res.append('0');
343         }
344     }
345     return res;
346 }
347 
348 QString watermark::array2str(byteArray &array)
349 {
350     QString res;
351     for(int i = 0 ; i<array.length(); i+=8)
352     {
353         int num = array[i + 7] + array[i + 6]*2 + array[i + 5]*4 + array[i + 4]*8 +
354                 array[i + 3]*16 + array[i + 2]*32 + array[i + 1]*64 + array[i + 0]*128;
355         res.append(char(num));
356     }
357     return res;
358 }
359 
360 // encode byteArray with keyArray
361 byteArray watermark::encode(byteArray src, byteArray key)
362 {
363     byteArray res;
364     if(src.length() != key.length())
365     {
366         qDebug()<< "The length of keyArray and srcArray doesn't match! ";
367         return byteArray();
368     }
369 
370     for(int i = 0; i < src.length(); i++)
371     {
372         res.append(src[i] ^ key[i]);
373     }
374 
375     return res;
376 }
377 
378 /*
379 BITMAPINFODEADER &watermark::operator=(BITMAPINFODEADER& BMIH)
380 {
381     if( &((*this).BMIH) == &BMIH )
382         return (*this).BMIH;
383     BMIH.biSize = (*this).BMIH.biSize;
384     BMIH.biWidth = (*this).BMIH.biWidth;
385     BMIH.biHeight = (*this).BMIH.biHeight;
386     BMIH.biPlanes = (*this).BMIH.biPlanes;
387     BMIH.biClrUsed = (*this).BMIH.biClrUsed;
388     BMIH.biSizeImage = (*this).BMIH.biSizeImage;
389     BMIH.biCompression = (*this).BMIH.biCompression;
390     BMIH.biClrImportant = (*this).BMIH.biClrImportant;
391     BMIH.biXPelsPerMeter = (*this).BMIH.biXPelsPerMeter;
392     BMIH.biYPelsPerMeter = (*this).BMIH.biYPelsPerMeter;
393     qDebug() << "214235423" << endl;
394     //return (*this).BMIH;
395     return BMIH;
396 }
397 */
  1 #include "mainwindow.h"
  2 #include "ui_mainwindow.h"
  3 
  4 #include <QtCore>
  5 #include <QFile>
  6 #include <QFileDialog>
  7 #include <QMessageBox>
  8 
  9 #include "bmputil.h"
 10 //#include "bmputil.cpp"
 11 
 12 MainWindow::MainWindow(QWidget *parent) :
 13     QMainWindow(parent),
 14     ui(new Ui::MainWindow)
 15 {
 16     ui->setupUi(this);
 17     image = QPixmap();
 18 
 19     QStringList bands = QStringList() << "QString" << "byteArray";
 20     ui->comboBoxWaterMark->setModel(new QStringListModel(bands));
 21     ui->comboBoxWaterMark->setCurrentIndex(1);
 22     ui->lineEditWaterMark->setText("01010101010101010101010101010101");
 23 }
 24 
 25 MainWindow::~MainWindow()
 26 {
 27     delete ui;
 28 }
 29 
 30 void MainWindow::on_pushButtonBrowse_clicked()
 31 {
 32     auto file = QFileDialog::getOpenFileName(this, tr("Append selected images"));
 33     ui->lineEdit->setText(file);
 34 }
 35 
 36 void MainWindow::on_lineEdit_textChanged(const QString &arg1)
 37 {
 38     Q_UNUSED(arg1);
 39     watermark WT;
 40     if(QFileInfo(ui->lineEdit->displayText()).exists())
 41     {
 42         int height, width;
 43         uchar* buffer = WT.readBmp(ui->lineEdit->displayText().toStdString().data(), width, height);
 44         if(buffer)
 45         {
 46             QPixmap img = QPixmap::fromImage(QImage(buffer, width, height, QImage::Format_Grayscale8));
 47             QGraphicsScene *scene = new QGraphicsScene;
 48             scene->addPixmap(img);
 49             ui->graphicsViewPrevious->setScene(scene);
 50             ui->graphicsViewPrevious->show();
 51             ui->graphicsViewPrevious->fitInView(img.rect(), Qt::KeepAspectRatio);
 52         }
 53     }
 54 }
 55 
 56 void MainWindow::on_pushButtonEncode_clicked()
 57 {
 58     byteArray code;
 59     watermark WT;
 60     if(ui->comboBoxWaterMark->currentIndex() == 1)
 61     {
 62         QRegExp regx("[0-1]+$");
 63         QValidator *validator = new QRegExpValidator(regx, this );
 64         ui->lineEditWaterMark->setValidator( validator );
 65         QString str1 = ui->lineEditWaterMark->text();
 66         code = WT.byte2Array(str1);
 67         delete validator;
 68     }
 69     else
 70     {
 71         QRegExp regx(".+\n");
 72         QValidator *validator = new QRegExpValidator(regx, this );
 73         ui->lineEditWaterMark->setValidator( validator );
 74         QString str2 = ui->lineEditWaterMark->text();
 75         //code = str2Array(ui->lineEditWaterMark->text());
 76         code = WT.str2Array(str2);
 77         delete validator;
 78     }
 79     key = WT.generateKey(code.length());
 80     int width, height;
 81     uchar* buffer = WT.readBmp(ui->lineEdit->displayText().toStdString().data(), width, height);
 82     uchar* edge = WT.edgeExtract(buffer, width, height);
 83     dst = WT.watermarkImg(buffer, edge, width*height, WT.encode(code, key));
 84     //imwrite("encode.bmp", dst*255);
 85     image = QPixmap::fromImage(QImage(dst, width, height, QImage::Format_Grayscale8));
 86     QGraphicsScene *scene = new QGraphicsScene;
 87     scene->addPixmap(image);
 88     ui->graphicsViewAfter->setScene(scene);
 89     ui->graphicsViewAfter->show();
 90     ui->graphicsViewAfter->fitInView(image.rect(), Qt::KeepAspectRatio);
 91     //WT.saveBmp(dst);
 92     //qDebug() << "In void MainWindow::on_pushButtonEncode_clicked(), height = " << height << endl;
 93     //qDebug() << "void MainWindow::on_pushButtonEncode_clicked(), width = " << width << endl;
 94     WT.savebmp("encode.bmp", dst, height, width);
 95 }
 96 
 97 void MainWindow::on_pushButtonDecode_clicked()
 98 {
 99     int width, height;
100     watermark WT;
101     uchar* buffer = WT.readBmp(ui->lineEdit->displayText().toStdString().data(), width, height);
102     byteArray code = WT.encode(WT.decodeImg(buffer, dst, width, height, key.length()), key);
103     if(ui->comboBoxWaterMark->currentIndex() == 1)
104     {
105         QMessageBox::warning(this, "Decode", "The watermark is " + WT.array2byte(code)+"!");
106     }
107     if(ui->comboBoxWaterMark->currentIndex() == 0)
108     {
109         QMessageBox::warning(this, "Decode", "The watermark is " + WT.array2str(code)+"!");
110     }
111 }
 1 #include "mainwindow.h"
 2 #include <QApplication>
 3 
 4 int main(int argc, char *argv[])
 5 {
 6     QApplication a(argc, argv);
 7     MainWindow w;
 8     w.setWindowTitle("8 bits Binary BMP picture watermarking program");
 9     w.show();
10 
11     return a.exec();
12 }

猜你喜欢

转载自www.cnblogs.com/25th-engineer/p/10817923.html