不使用cv库实现图像油漆效果给出代码,手动读写bmp文件,用c语言实现
时间: 2024-02-27 20:52:48 浏览: 213
基于OpenCV实现的图像油画效果处理程序(高效率低耗时C++代码-带详细注释)
5星 · 资源好评率100%
以下是一种用C语言实现图像油漆效果的简单方法,手动读写bmp文件:
```c
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <time.h>
// 定义BMP文件头结构体
typedef struct {
uint16_t type; // 文件类型,固定为0x4d42
uint32_t size; // 文件大小(字节)
uint16_t reserved1; // 保留字段1,固定为0
uint16_t reserved2; // 保留字段2,固定为0
uint32_t offset; // 数据偏移量(字节)
} BMPHeader;
// 定义BMP文件信息头结构体
typedef struct {
uint32_t size; // 信息头大小(字节),固定为40
int32_t width; // 图像宽度(像素)
int32_t height; // 图像高度(像素)
uint16_t planes; // 色彩平面数,固定为1
uint16_t bit_count; // 每个像素的位数,固定为24
uint32_t compression; // 压缩方式,固定为0
uint32_t size_image; // 图像数据大小(字节)
int32_t x_pels_per_meter; // 水平分辨率(像素/米),可忽略
int32_t y_pels_per_meter; // 垂直分辨率(像素/米),可忽略
uint32_t clr_used; // 调色板使用的颜色数,可忽略
uint32_t clr_important; // 重要的颜色数,可忽略
} BMPInfoHeader;
// 读取BMP文件头信息
void read_bmp_header(FILE* f, BMPHeader* header) {
fread(&header->type, sizeof(header->type), 1, f);
fread(&header->size, sizeof(header->size), 1, f);
fread(&header->reserved1, sizeof(header->reserved1), 1, f);
fread(&header->reserved2, sizeof(header->reserved2), 1, f);
fread(&header->offset, sizeof(header->offset), 1, f);
}
// 读取BMP文件信息头信息
void read_bmp_info_header(FILE* f, BMPInfoHeader* header) {
fread(&header->size, sizeof(header->size), 1, f);
fread(&header->width, sizeof(header->width), 1, f);
fread(&header->height, sizeof(header->height), 1, f);
fread(&header->planes, sizeof(header->planes), 1, f);
fread(&header->bit_count, sizeof(header->bit_count), 1, f);
fread(&header->compression, sizeof(header->compression), 1, f);
fread(&header->size_image, sizeof(header->size_image), 1, f);
fread(&header->x_pels_per_meter, sizeof(header->x_pels_per_meter), 1, f);
fread(&header->y_pels_per_meter, sizeof(header->y_pels_per_meter), 1, f);
fread(&header->clr_used, sizeof(header->clr_used), 1, f);
fread(&header->clr_important, sizeof(header->clr_important), 1, f);
}
// 写入BMP文件头信息
void write_bmp_header(FILE* f, const BMPHeader* header) {
fwrite(&header->type, sizeof(header->type), 1, f);
fwrite(&header->size, sizeof(header->size), 1, f);
fwrite(&header->reserved1, sizeof(header->reserved1), 1, f);
fwrite(&header->reserved2, sizeof(header->reserved2), 1, f);
fwrite(&header->offset, sizeof(header->offset), 1, f);
}
// 写入BMP文件信息头信息
void write_bmp_info_header(FILE* f, const BMPInfoHeader* header) {
fwrite(&header->size, sizeof(header->size), 1, f);
fwrite(&header->width, sizeof(header->width), 1, f);
fwrite(&header->height, sizeof(header->height), 1, f);
fwrite(&header->planes, sizeof(header->planes), 1, f);
fwrite(&header->bit_count, sizeof(header->bit_count), 1, f);
fwrite(&header->compression, sizeof(header->compression), 1, f);
fwrite(&header->size_image, sizeof(header->size_image), 1, f);
fwrite(&header->x_pels_per_meter, sizeof(header->x_pels_per_meter), 1, f);
fwrite(&header->y_pels_per_meter, sizeof(header->y_pels_per_meter), 1, f);
fwrite(&header->clr_used, sizeof(header->clr_used), 1, f);
fwrite(&header->clr_important, sizeof(header->clr_important), 1, f);
}
// 读取BMP文件像素数据
void read_pixel_data(FILE* f, uint8_t* data, uint32_t size) {
fread(data, size, 1, f);
}
// 写入BMP文件像素数据
void write_pixel_data(FILE* f, const uint8_t* data, uint32_t size) {
fwrite(data, size, 1, f);
}
// 定义参数
#define BRUSH_SIZE 10
#define BRUSH_DENSITY 50
#define COLOR_VARIATION 20
// 生成随机颜色
void generate_random_color(uint8_t* color) {
color[0] = rand() % 256;
color[1] = rand() % 256;
color[2] = rand() % 256;
}
int main() {
// 打开输入文件
FILE* input_file = fopen("image.bmp", "rb");
if (!input_file) {
printf("Failed to open input file\n");
return 1;
}
// 读取BMP文件头和信息头
BMPHeader header;
BMPInfoHeader info_header;
read_bmp_header(input_file, &header);
read_bmp_info_header(input_file, &info_header);
// 计算每行像素数据占用的字节数
uint32_t row_size = (info_header.width * 3 + 3) / 4 * 4;
// 计算像素数据总大小
uint32_t data_size = row_size * info_header.height;
// 分配内存存储像素数据
uint8_t* pixel_data = malloc(data_size);
if (!pixel_data) {
printf("Failed to allocate memory\n");
fclose(input_file);
return 1;
}
// 读取像素数据
read_pixel_data(input_file, pixel_data, data_size);
// 关闭输入文件
fclose(input_file);
// 打开输出文件
FILE* output_file = fopen("output.bmp", "wb");
if (!output_file) {
printf("Failed to open output file\n");
free(pixel_data);
return 1;
}
// 写入BMP文件头和信息头
write_bmp_header(output_file, &header);
write_bmp_info_header(output_file, &info_header);
// 初始化随机数生成器
srand(time(NULL));
// 循环遍历每个像素
for (int y = 0; y < info_header.height; y++) {
for (int x = 0; x < info_header.width; x++) {
// 计算该像素在像素数据数组中的索引
uint32_t index = (info_header.height - y - 1) * row_size + x * 3;
// 确定该区域是否需要涂刷
if (rand() % 100 > BRUSH_DENSITY) {
continue;
}
// 获取该区域内的像素颜色,并随机变化一些颜色值
uint8_t color[3];
generate_random_color(color);
color[0] = pixel_data[index] + (rand() % (COLOR_VARIATION * 2 + 1) - COLOR_VARIATION);
color[1] = pixel_data[index + 1] + (rand() % (COLOR_VARIATION * 2 + 1) - COLOR_VARIATION);
color[2] = pixel_data[index + 2] + (rand() % (COLOR_VARIATION * 2 + 1) - COLOR_VARIATION);
for (int i = 0; i < BRUSH_SIZE; i++) {
for (int j = 0; j < BRUSH_SIZE; j++) {
if (x + i < info_header.width && y + j < info_header.height) {
// 计算该像素在像素数据数组中的索引
uint32_t brush_index = (info_header.height - y - 1 - j) * row_size + (x + i) * 3;
pixel_data[brush_index] = color[0];
pixel_data[brush_index + 1] = color[1];
pixel_data[brush_index + 2] = color[2];
}
}
}
}
}
// 写入像素数据
write_pixel_data(output_file, pixel_data, data_size);
// 关闭输出文件
fclose(output_file);
// 释放内存
free(pixel_data);
return 0;
}
```
该代码使用C语言中的文件操作函数手动读取BMP文件头信息和像素数据,然后遍历每个像素,并随机确定是否在该区域内涂刷颜色。如果确定要涂刷,它会获取该区域内的像素颜色,并随机变化一些颜色值,然后在该区域内用随机颜色填充一个小矩形。最后,将新的像素数据写入输出文件中。注意,由于BMP文件像素数据存储顺序是从底部到顶部、从左到右,因此需要使用一些计算来确定每个像素在像素数据数组中的索引。
阅读全文