用C语言编写数字水印的完整算法
时间: 2024-05-11 09:18:44 浏览: 188
脆弱水印相关算法及代码实现
4星 · 用户满意度95%
数字水印是在数字媒体中嵌入隐藏信息的技术,可以用于版权保护、身份认证等方面。以下是用C语言编写数字水印的完整算法:
1. 选择一种数字水印算法,比如DCT变换算法。该算法将嵌入的信息转换成数字信号,然后将其嵌入到原始图像的频率域中。
2. 读取原始图像,将其转换成灰度图像。将灰度值映射到0~255之间。
3. 对灰度图像进行DCT变换,得到频率域图像。
4. 将嵌入的信息转换成二进制序列,比如10010110。
5. 将二进制序列嵌入到频率域图像的某些系数中,比如将前8个系数的最后一位分别替换为二进制序列中的每一位。
6. 对修改后的频率域图像进行IDCT变换,得到嵌入了数字水印的图像。
7. 将嵌入了数字水印的图像保存到文件中。
以下是一个简单的示例代码:
```c
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#define BLOCK_SIZE 8 // DCT块大小
#define WATERMARK_LEN 8 // 数字水印长度
// DCT变换
void dct(double* block) {
double c[BLOCK_SIZE][BLOCK_SIZE];
double tmp[BLOCK_SIZE][BLOCK_SIZE];
for (int i = 0; i < BLOCK_SIZE; i++) {
for (int j = 0; j < BLOCK_SIZE; j++) {
if (i == 0) {
c[i][j] = 1 / sqrt(BLOCK_SIZE);
} else {
c[i][j] = sqrt(2.0 / BLOCK_SIZE) * cos((2 * j + 1) * i * M_PI / (2 * BLOCK_SIZE));
}
}
}
for (int u = 0; u < BLOCK_SIZE; u++) {
for (int v = 0; v < BLOCK_SIZE; v++) {
double sum = 0.0;
for (int i = 0; i < BLOCK_SIZE; i++) {
for (int j = 0; j < BLOCK_SIZE; j++) {
sum += block[i * BLOCK_SIZE + j] * c[i][u] * c[j][v];
}
}
tmp[u][v] = sum;
}
}
for (int i = 0; i < BLOCK_SIZE; i++) {
for (int j = 0; j < BLOCK_SIZE; j++) {
block[i * BLOCK_SIZE + j] = tmp[i][j];
}
}
}
// IDCT变换
void idct(double* block) {
double c[BLOCK_SIZE][BLOCK_SIZE];
double tmp[BLOCK_SIZE][BLOCK_SIZE];
for (int i = 0; i < BLOCK_SIZE; i++) {
for (int j = 0; j < BLOCK_SIZE; j++) {
if (i == 0) {
c[i][j] = 1 / sqrt(BLOCK_SIZE);
} else {
c[i][j] = sqrt(2.0 / BLOCK_SIZE) * cos((2 * j + 1) * i * M_PI / (2 * BLOCK_SIZE));
}
}
}
for (int u = 0; u < BLOCK_SIZE; u++) {
for (int v = 0; v < BLOCK_SIZE; v++) {
double sum = 0.0;
for (int i = 0; i < BLOCK_SIZE; i++) {
for (int j = 0; j < BLOCK_SIZE; j++) {
sum += c[i][u] * c[j][v] * block[i * BLOCK_SIZE + j];
}
}
tmp[u][v] = sum;
}
}
for (int i = 0; i < BLOCK_SIZE; i++) {
for (int j = 0; j < BLOCK_SIZE; j++) {
block[i * BLOCK_SIZE + j] = tmp[i][j];
}
}
}
// 将数字转换为二进制序列
void int2bin(unsigned char* bin, int num) {
for (int i = 0; i < 8; i++) {
bin[i] = (num & (1 << i)) ? 1 : 0;
}
}
// 将二进制序列转换为数字
int bin2int(unsigned char* bin) {
int num = 0;
for (int i = 0; i < 8; i++) {
num += bin[i] * (1 << i);
}
return num;
}
int main() {
FILE* fp = fopen("lena.bmp", "rb");
if (!fp) {
printf("Failed to open file.\n");
return -1;
}
unsigned char header[54];
fread(header, sizeof(unsigned char), 54, fp);
int width = *(int*)&header[18];
int height = *(int*)&header[22];
int bit_depth = *(int*)&header[28];
int row_size = (width * bit_depth + 31) / 32 * 4;
unsigned char* data = (unsigned char*)malloc(row_size * height);
fread(data, sizeof(unsigned char), row_size * height, fp);
fclose(fp);
unsigned char* watermark = (unsigned char*)malloc(WATERMARK_LEN);
int2bin(watermark, 0x5a); // 嵌入数字水印
for (int y = 0; y < height; y += BLOCK_SIZE) {
for (int x = 0; x < width; x += BLOCK_SIZE) {
double block[BLOCK_SIZE * BLOCK_SIZE];
for (int i = 0; i < BLOCK_SIZE; i++) {
for (int j = 0; j < BLOCK_SIZE; j++) {
int index = (y + i) * row_size + (x + j) * bit_depth / 8;
block[i * BLOCK_SIZE + j] = data[index];
}
}
dct(block); // DCT变换
for (int i = 0; i < WATERMARK_LEN; i++) {
int index = i % BLOCK_SIZE * BLOCK_SIZE + i / BLOCK_SIZE;
block[index] = (int)block[index] & 0xfe | watermark[i]; // 嵌入数字水印
}
idct(block); // IDCT变换
for (int i = 0; i < BLOCK_SIZE; i++) {
for (int j = 0; j < BLOCK_SIZE; j++) {
int index = (y + i) * row_size + (x + j) * bit_depth / 8;
data[index] = (unsigned char)block[i * BLOCK_SIZE + j];
}
}
}
}
fp = fopen("lena_watermark.bmp", "wb");
fwrite(header, sizeof(unsigned char), 54, fp);
fwrite(data, sizeof(unsigned char), row_size * height, fp);
fclose(fp);
free(data);
free(watermark);
return 0;
}
```
该代码读取了名为lena.bmp的图像文件,将其转换为灰度图像,并将长度为8的数字水印0x5a嵌入到DCT块中。具体地,将DCT块中前8个系数的最后一位分别替换为数字水印中的每一位。最后将嵌入了数字水印的图像保存到名为lena_watermark.bmp的文件中。
阅读全文