某垃圾大学数据结果课程设计(题目抄袭自某牛逼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 }