RGB源数据操作: 实现图片放大、缩小

简介: RGB源数据操作: 实现图片放大、缩小

一、运行环境介绍

Linux系统: Redhat6.3 (32位)


gcc 版本 4.4.6 20120305 (Red Hat 4.4.6-4) (GCC)


二、功能介绍

打开一张BMP图片,读取RGB源数据进行缩放再生成新的BMP图片。


三、核心代码

由于处理的是BMP图片数据,传入的缩放后的图片宽度需要是4的倍数.


缩放算法参考: http://blog.chinaunix.net/uid-22915173-id-2185545.html

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int PicZoom(unsigned char *s_buff,unsigned int s_width,unsigned int s_height,unsigned char *buff,unsigned int width,unsigned int height);
void *my_memcpy(void *v_dst,const void *v_src,unsigned char c);
#pragma pack(1)   /* 必须在结构体定义之前使用,这是为了让结构体中各成员按1字节对齐 */
/*需要文件信息头:14个字节 */
struct BITMAPFILEHEADER
{
  unsigned short bfType;      //保存图片类似。 'BM'
  unsigned long  bfSize;      //图片的大小
  unsigned short bfReserved1;
  unsigned short bfReserved2;
  unsigned long  bfOffBits;  //RGB数据偏移地址
};
/* 位图信息头 */
struct BITMAPINFOHEADER { /* bmih */
  unsigned long  biSize;      //结构体大小
  unsigned long  biWidth;   //宽度
  unsigned long  biHeight;  //高度
  unsigned short biPlanes;
  unsigned short biBitCount;  //颜色位数
  unsigned long  biCompression;
  unsigned long  biSizeImage;
  unsigned long  biXPelsPerMeter;
  unsigned long  biYPelsPerMeter;
  unsigned long  biClrUsed;
  unsigned long  biClrImportant;
};
/*
图片放大与缩小示例
*/
int main(int argc,char *argv[])
{
  struct BITMAPFILEHEADER src_head;  //源文件头数据
  struct BITMAPINFOHEADER src_info;  //源文件参数结构
  struct BITMAPFILEHEADER new_head;  //新文件头数据
  struct BITMAPINFOHEADER new_info;  //新文件参数结构
  unsigned int new_Width;        //缩放后的宽度
  unsigned int new_Height;       //缩放后的高度
  unsigned char *new_buff;           //存放新图片的数据
  unsigned char *src_buff;           //存放源图片的数据
  unsigned int cnt=0;
    if(argc!=5)
    {
        printf("参数格式: ./a.out <原图片名称> <新图片名称> <缩放后宽度> <缩放后高度>\n");
        printf("例如: ./a.out src.bmp new.bmp 80 80 \n");
        return 0;
    }
  /*1. 打开图片文件*/
  FILE *src_file=fopen(argv[1],"rb");
  FILE *new_file=fopen(argv[2],"wb");
  if(src_file==NULL||new_file==NULL)
  {
    printf("%s 源文件打开失败!\r\n",argv[1]);
    return;
  }
  /*2. 读取源图片参数*/
  fread(&src_head,sizeof(struct BITMAPFILEHEADER),1,src_file);
  fread(&src_info,sizeof(struct BITMAPINFOHEADER),1,src_file);
  printf("源图片尺寸:w=%d h=%d\r\n",src_info.biWidth,src_info.biHeight);
  /*3. 获取新图片的尺寸*/
    new_Width=atoi(argv[3]);
    new_Height=atoi(argv[4]);
  printf("新图片尺寸:w=%d h=%d\r\n",new_Width,new_Height);
  /*4. 申请存放图片数据的空间*/
  src_buff=malloc(src_info.biWidth*src_info.biHeight*3);
  new_buff=malloc(new_Width*new_Height*3);
  if(new_buff==NULL||src_buff==NULL)
  {
    printf("malloc申请空间失败!\r\n");
    return -1;
  }
  /*5. 读取源图片RGB数据*/
  fseek(src_file,src_head.bfOffBits,SEEK_SET); //移动文件指针到RGB数据位置
  fread(src_buff,1,src_info.biWidth*src_info.biHeight*3,src_file); //读取源数据
  /*6. 缩放图片*/
  if(PicZoom(src_buff,src_info.biWidth,src_info.biHeight,new_buff,new_Width,new_Height))
  {
    printf("图片缩放处理失败!\r\n");
    return -1;
  }
  /*7. 写入新图片数据*/
  //填充文件头
  memset(&new_head,0,sizeof(struct BITMAPFILEHEADER));
  new_head.bfType=0x4d42;
  new_head.bfSize=54+new_Width*new_Height*3;
  new_head.bfOffBits=54;
  //填充文件参数
  memset(&new_info,0,sizeof(struct BITMAPINFOHEADER));
  new_info.biSize=sizeof(struct BITMAPINFOHEADER);
  new_info.biWidth=new_Width;
  new_info.biHeight=new_Height;
  new_info.biPlanes=1;
  new_info.biBitCount=24;
  //写入文件数据
  fwrite(&new_head,sizeof(struct BITMAPFILEHEADER),1,new_file);
  fwrite(&new_info,sizeof(struct BITMAPINFOHEADER),1,new_file);
  fseek(new_file,new_head.bfOffBits,SEEK_SET); //移动文件指针到RGB数据位置
  cnt=fwrite(new_buff,1,new_info.biWidth*new_info.biHeight*3,new_file); //写数据
  /*8. 关闭图片文件*/
  fclose(new_file);
  fclose(src_file);
  printf("%s 新图片创建成功! 路径:程序运行路径下\r\n",argv[2]);
  return 0;
}
/**********************************************************************
* 函数名称: PicZoom
* 功能描述: 近邻取样插值方法缩放图片
*            注意该函数会分配内存来存放缩放后的图片,用完后要用free函数释放掉
*            "近邻取样插值"的原理请参考网友"lantianyu520"所著的"图像缩放算法"
* 输入参数:  ptOriginPic - 内含原始图片的象素数据
*             ptZoomPic    - 内含缩放后的图片的象素数据
* 输出参数: 无
* 返 回 值: 0 - 成功, 其他值 - 失败
***********************************************************************/
int PicZoom(unsigned char *ptOriginPic_aucPixelDatas,unsigned int ptOriginPic_iWidth,unsigned int ptOriginPic_iHeight,unsigned char *ptZoomPic_aucPixelDatas,unsigned int ptZoomPic_iWidth,unsigned int ptZoomPic_iHeight)
{
  unsigned int ptOriginPic_iLineBytes=ptOriginPic_iWidth*3; //一行的字节数
  unsigned int ptZoomPic_iLineBytes=ptZoomPic_iWidth*3;  //一行的字节数
  unsigned long dwDstWidth=ptZoomPic_iWidth;
  unsigned long* pdwSrcXTable;
  unsigned long x;
  unsigned long y;
  unsigned long dwSrcY;
  unsigned char *pucDest;
  unsigned char *pucSrc;
  unsigned long dwPixelBytes=3; //像素字节
  pdwSrcXTable=malloc(sizeof(unsigned long) * dwDstWidth);
  if(NULL==pdwSrcXTable)
  {
    return -1;
  }
  for(x=0; x < dwDstWidth; x++)//生成表 pdwSrcXTable
  {
    pdwSrcXTable[x]=(x*ptOriginPic_iWidth/ptZoomPic_iWidth);
  }
  for(y=0; y < ptZoomPic_iHeight; y++)
  {
    dwSrcY=(y * ptOriginPic_iHeight/ptZoomPic_iHeight);
    pucDest=ptZoomPic_aucPixelDatas + y * ptZoomPic_iLineBytes;
    pucSrc=ptOriginPic_aucPixelDatas+dwSrcY * ptOriginPic_iLineBytes;
    for(x=0; x <dwDstWidth; x++)
    {
      my_memcpy(pucDest+x*dwPixelBytes,pucSrc+pdwSrcXTable[x]*dwPixelBytes,dwPixelBytes);
    }
  }
  free(pdwSrcXTable);
  return 0;
}
/*
函数功能:内存拷贝函数
*/
void *my_memcpy(void *v_dst,const void *v_src,unsigned char c)
{
  const char *src=v_src;
  char *dst=v_dst;
  while(c--)*dst++=*src++;
  return v_dst;
}

四、运行示例

[wbyq@wbyq linux_c]$ gcc app.c 
[wbyq@wbyq linux_c]$ ./a.out 
参数格式: ./a.out <原图片名称> <新图片名称> <缩放后宽度> <缩放后高度>
例如: ./a.out src.bmp new.bmp 80 80 
[wbyq@wbyq linux_c]$ ./a.out 666.bmp 1.bmp 80 80
源图片尺寸:w=800 h=383
新图片尺寸:w=80 h=80
1.bmp 新图片创建成功! 路径:程序运行路径下
[wbyq@wbyq linux_c]$ eog 1.bmp 

image.png

目录
相关文章
EMQ
|
Linux 网络性能优化
MQTT 5.0 报文解析 03:SUBSCRIBE 与 UNSUBSCRIBE
在 MQTT 中,SUBSCRIBE 报文用于发起订阅请求,SUBACK 报文用于返回订阅结果。而 UNSUBSCRIBE 和 UNSUBACK 报文则在取消订阅时使用。相比于取消订阅,订阅操作更加常用。不过在本文中,我们仍然会一并介绍订阅与取消订阅报文的结构与组成。
EMQ
741 94
MQTT 5.0 报文解析 03:SUBSCRIBE 与 UNSUBSCRIBE
|
机器学习/深度学习 算法 算法框架/工具
为什么使用C++进行机器学习开发
C++作为一种高性能语言,在某些性能要求极高或资源受限的场景下也具有非常重要的地位。C++的高效性和对底层硬件的控制能力,使其在大规模机器学习系统中发挥重要作用,尤其是当需要处理大数据或实时响应的系统时。
258 3
|
JavaScript 前端开发
将base64格式的图片画到canvas上(js和vue两种)
将base64格式的图片画到canvas上(js和vue两种)
1017 1
|
Linux Shell
Linux系统编程:掌握popen函数的使用
记得在使用完 `popen`打开的流后,总是使用 `pclose`来正确关闭它,并回收资源。这种做法符合良好的编程习惯,有助于保持程序的健壮性和稳定性。
678 6
|
机器学习/深度学习 存储 PyTorch
深度学习训练时混合精度的作用
在深度学习训练过程中,混合精度(Mixed Precision)是指同时使用不同的数值精度(如16位浮点数和32位浮点数)来进行计算。
367 2
|
机器学习/深度学习 算法 决策智能
Python求解旅行商问题
欢迎关注我的微信公众号:Python学习杂记
541 0
|
存储 安全 Shell
【Shell 命令集合 磁盘维护】Linux 检测和识别硬盘或文件系统中的坏块 badblocks命令使用教程
【Shell 命令集合 磁盘维护】Linux 检测和识别硬盘或文件系统中的坏块 badblocks命令使用教程
595 0
|
存储 虚拟化 数据库
蓝易云 - 什么是云服务器?个人拥有一台云服务器能干什么?
云服务器,也称为虚拟私有服务器(VPS),是一种提供在线服务的服务器,它在物理服务器上虚拟化并分配给用户。云服务器可以提供与物理服务器相同的功能和性能,但是用户可以根据需要调整其资源配置,如CPU、内存和存储等。
369 0
|
Go 内存技术
【Jlink】JLink Commander调试方法
上面的信息连可以看到当前运行的PC指针,再可以结合生成的map文件,就可以看到当前运行的函数。例如上面运行的PC指针为0x01000E72,下图是固件的map文件,查看map文件对应地址的函数为SEGGER_RTT_Write。用来读取内存的数据,参数为内存的地址和读取的长度。也可以直接用mem命令按照8位来读取。常用的命令有halt,go,mem(mem8,mem16, mem32), write(write1, write2, write4 )用来写入对应的内存地址,参数为内存的地址和写入的数据。
3263 45
【Jlink】JLink Commander调试方法
|
算法 调度
FreeRTOS入门教程(任务优先级,Tick)
FreeRTOS入门教程(任务优先级,Tick)
1112 0