// jpage 解码库 libjpeg_turbo
#include "jpeglib.h"
/*
* 功能:解码jpeg图像到指定格式
* 参数:
* injpeg 输入图像数据指针 可选
* inLen 对应数据长度 可选
* infile 输入图像文件指针
* out 输出解码后的数据
* outFormat 输出图形格式
* imgWidth 获取到的 图像宽度
* imgHeight 获取到的 图像高度
*/
int JPGdecode(char* injpeg, int inLen, FILE * infile, char* out, int outFormat, int *imgWidth, int *imgHeight)
{
int ret = 0;
int rowStride = 0;
int ySize = 0;
int uvSize = 0;
char* yPtr = NULL;
char* uPtr = NULL;
char* vPtr = NULL;
char* uvPtr = NULL;
char *RowBuffer = NULL;
struct jpeg_decompress_struct dinfo;// 此结构包含JPEG解压缩参数和指针 工作空间(根据JPEG库的需要分配)
struct jpeg_error_mgr jerr; // 我们使用我们的专用扩展名JPEG错误处理程序
struct jpeg_source_mgr s_mgr(unsigned char *injpeg, int inLen);
dinfo.err = jpeg_std_error(&jerr); // 我们设置正常的JPEG错误例程
jpeg_create_decompress(&dinfo); // 1.初始化JPEG解压缩对象
dinfo.src = &s_mgr; // 2.指定数据源(例如文件)
//jpeg_stdio_src(&dinfo, infile); // 输入jpeg图像文件指针模式
int status = jpeg_read_header(&dinfo, TRUE);// 3.用jpeg_read_header()读取文件参数
if (status != JPEG_HEADER_OK)
{
printf("jpeg header corrupted");
jpeg_destroy_decompress(&dinfo);
return ret;
}
dinfo.out_color_space = JCS_YCbCr; // 4. 设置解压缩参数 不设置默认为 rgb格式
//dinfo.raw_data_out = true;
// 放大缩小参数
// dinfo.scale_num=4; // 分子
// dinfo.scale_denom=5; // 分母
// 通过scale_num / scale_denom分数缩放图像。
// 默认值是1 / 1,或不缩放。目前,唯一支持的缩放比率是M / 8,所有M从1到16,或其任何缩小比例(例如1 / 2,3 / 4等)
status = jpeg_start_decompress(&dinfo); // 5. 开始解码
if (!status)
{
printf("jpeg_start_decompress failed");
return ret;
}
*imgWidth = dinfo.output_width;
*imgHeight = dinfo.output_height;
rowStride = dinfo.output_width * dinfo.output_components;//一行的数据长度
RowBuffer = (char*)malloc(rowStride*sizeof(JSAMPLE)); // 行数据空间
ySize = dinfo.output_width * dinfo.output_height; // 一个通道数据量
ret = ySize * 3 / 2;
if (outFormat == 0) // HIK_PIXEL_FORMAT_NV21
{
yPtr = out;
uvPtr = out + ySize;
// 循环调用jpeg_read_scanlines来一行一行地获得解压的数据
while (dinfo.output_scanline < dinfo.output_height)
{
(void)jpeg_read_scanlines(&dinfo, (JSAMPARRAY)&RowBuffer, 1);
if (dinfo.output_scanline % 2 == 0)
{
YuvToNV21Line(RowBuffer, yPtr, uvPtr, dinfo.output_width, TRUE);
uvPtr += dinfo.output_width;
}
else
{
YuvToNV21Line(RowBuffer, yPtr, uvPtr, dinfo.output_width, TRUE);
}
yPtr += dinfo.output_width;
}
}
else if (outFormat == 1) // HIK_PIXEL_FORMAT_NV12
{
yPtr = out;
uvPtr = out + ySize;
while (dinfo.output_scanline < dinfo.output_height)
{
(void)jpeg_read_scanlines(&dinfo, (JSAMPARRAY)&RowBuffer, 1);
if (dinfo.output_scanline % 2 == 0)
{
YuvToNV12Line(RowBuffer, yPtr, uvPtr, dinfo.output_width, TRUE);
uvPtr += dinfo.output_width;
}
else
{
YuvToNV12Line(RowBuffer, yPtr, uvPtr, dinfo.output_width, TRUE);
}
yPtr += dinfo.output_width;
}
}
else if (outFormat == 2)// HIK_PIXEL_FORMAT_YV12
{
yPtr = out;
uPtr = out + ySize;
vPtr = uPtr + (ySize / 4);
while (dinfo.output_scanline < dinfo.output_height)
{
(void)jpeg_read_scanlines(&dinfo, (JSAMPARRAY)&RowBuffer, 1);
if (dinfo.output_scanline % 2 == 0)
{
YuvToYV12Line(RowBuffer, yPtr, uPtr, vPtr, dinfo.output_width, TRUE);
vPtr += (dinfo.output_width / 2);
uPtr += (dinfo.output_width / 2);
}
else
{
YuvToYV12Line(RowBuffer, yPtr, uPtr, vPtr, dinfo.output_width, TRUE);
}
yPtr += dinfo.output_width;
}
}
else
{
printf("unsupport format(%d)", outFormat);
}
jpeg_finish_decompress(&dinfo); // 7. 完成解压缩
jpeg_destroy_decompress(&dinfo);// 8. 释放JPEG解压缩对象
if (NULL != RowBuffer)
{
free(RowBuffer);
}
return ret;
}
opencv
/***************************************************************************************************
* 功 能: 读取图像数据转换成 bbbgggrrr格式后保存
* 参 数: img_path - I 图像路径
* dst_w - I 目标图像宽度
* dst_h - I 目标图像高度
* save_file_path - I 目标图像保存路径
* 返回值: 状态码
***************************************************************************************************/
int read_image_data_to_rrggbb(char *img_path,
int dst_w,
int dst_h,
char *save_file_path)
{
int i, j, k;
if (NULL == img_path || (NULL == save_file_path))
{
printf("path error \r\n");
return 0;
}
IplImage *src_img = cvLoadImage((LPSTR)(LPCTSTR)img_path); // opencv载入图像
//int src_w = src_img->width; // 原图像长宽
//int src_h = src_img->height;
if (NULL == src_img)
{
printf("read img error,path:%s \r\n", img_path);
return -1;
}
unsigned char *dst_data = (unsigned char *)malloc(dst_w * dst_h * 3);// 3通道bgr图像 u8数据类型
IplImage *rsz_img = cvCreateImage(cvSize(dst_w, dst_h), src_img->depth, src_img->nChannels);
char *rsz_data = rsz_img->imageData;
cvResize(src_img, rsz_img); // 原图形变形到 目标尺寸
for (j = 0; j < dst_h; j++) // 每行
{
for (i = 0; i < dst_w; i++)// 每列
{
for (k = 0; k < 3; k++) // 3通道
{
int src_idx = j * dst_w * 3 + i * 3 + k; // 原图形数据 rgbrgbrgg排列
int dst_idx = dst_w * dst_h * k + j * dst_w + i;// 目标图像数据 bbbgggrrr排列
//dst_data[dst_idx] = (float)((unsigned char)rsz_data[src_idx]/* - 128*/)/* * 0.0078125*/; // 浮点类型数据 转换成0~1之间的数据
dst_data[dst_idx] = (unsigned char)rsz_data[src_idx];
}
}
}
cvReleaseImage(&src_img);
cvReleaseImage(&rsz_img);
FILE *file_out = fopen(save_file_path, "wb"); // 输出模型 可写 二进制格式
if (file_out == NULL)
{
printf("open file error :%s\n", save_file_path);
return 0;
}
fwrite(dst_data, 1, (dst_w * dst_h * 3), file_out);//保存图像数据
fclose(file_out);// 关闭文件
free(dst_data);
return 1;
}
/***************************************************************************************************
* 功 能: 读取图像数据转换成 bbbgggrrr格式后保存 填充空白到指定尺寸
* 参 数: img_path - I 图像路径
* dst_w - I 目标图像宽度
* dst_h - I 目标图像高度
* save_file_path - I 目标图像保存路径
* 返回值: 状态码
***************************************************************************************************/
int read_image_data_to_rrggbb_padding(char *img_path,
int dst_w,
int dst_h,
char *save_file_path)
{
int i, j, k;
if (NULL == img_path || (NULL == save_file_path))
{
printf("path error \r\n");
return 0;
}
IplImage *src_img = cvLoadImage((LPSTR)(LPCTSTR)img_path); // opencv载入图像
if (NULL == src_img)
{
printf("read img error,path:%s \r\n", img_path);
return -1;
}
int src_w = src_img->width; // 原图像长宽
int src_h = src_img->height;
char *src_data = src_img->imageData;
unsigned char *dst_data = (unsigned char *)malloc(dst_w * dst_h * 3);// 3通道bgr图像 u8数据类型
//IplImage *rsz_img = cvCreateImage(cvSize(dst_w, dst_h), src_img->depth, src_img->nChannels);
//char *rsz_data = rsz_img->imageData;
//cvResize(src_img, rsz_img); // 原图形变形到 目标尺寸
for (j = 0; j < dst_h; j++) // 每行
{
if (j < src_h)
{
for (i = 0; i < dst_w; i++)// 每列
{
if (i < src_w)
{
for (k = 0; k < 3; k++) // 3通道
{
//int src_idx = j * dst_w * 3 + i * 3 + k; // 原图形数据 rgbrgbrgg排列
//int dst_idx = dst_w * dst_h * k + j * dst_w + i;// 目标图像数据 bbbgggrrr排列
//dst_data[dst_idx] = (float)((unsigned char)rsz_data[src_idx]/* - 128*/)/* * 0.0078125*/; // 浮点类型数据 转换成0~1之间的数据
//dst_data[dst_idx] = (unsigned char)rsz_data[src_idx];
int src_idx = j * src_w * 3 + i * 3 + k; // 原图形数据 rgbrgbrgg排列
int dst_idx = dst_w * dst_h * k + j * dst_w + i;// 目标图像数据 bbbgggrrr排列
dst_data[dst_idx] = (unsigned char)src_data[src_idx];
}
}
else
{
}
}
}
else
{
}
}
cvReleaseImage(&src_img);
//cvReleaseImage(&rsz_img);
FILE *file_out = fopen(save_file_path, "wb"); // 输出模型 可写 二进制格式
if (file_out == NULL)
{
printf("open file error :%s\n", save_file_path);
return 0;
}
fwrite(dst_data, 1, (dst_w * dst_h * 3), file_out);//保存图像数据
fclose(file_out);// 关闭文件
free(dst_data);
return 1;
}
/* 读取图像img 缩放到固定尺寸 保存成 NV21图 y平铺 uv交织*/
int read_image_data_to_NV21(char *img_path,
int dst_w,
int dst_h,
char *save_file_path)
{
int i, j, k;
if (NULL == img_path || (NULL == save_file_path))
{
printf("path error \r\n");
return 0;
}
IplImage *src_img = cvLoadImage((LPSTR)(LPCTSTR)img_path); // opencv载入图像
//int src_w = src_img->width; // 原图像长宽
//int src_h = src_img->height;
if (NULL == src_img)
{
printf("read img error,path:%s \r\n", img_path);
return -1;
}
// 1. 缩放到 bgr图
unsigned char *dst_data = (unsigned char *)malloc(dst_w * dst_h * 3);// 3通道bgr图像 u8数据类型
unsigned char *dst_nv21_data = (unsigned char *)malloc(dst_w * dst_h * 3); // y + vu
IplImage *rsz_img = cvCreateImage(cvSize(dst_w, dst_h), src_img->depth, src_img->nChannels);
char *rsz_data = rsz_img->imageData;
cvResize(src_img, rsz_img); // 原图形变形到 目标尺寸
for (j = 0; j < dst_h; j++) // 每行
{
for (i = 0; i < dst_w; i++)// 每列
{
for (k = 0; k < 3; k++) // 3通道
{
int src_idx = j * dst_w * 3 + i * 3 + k; // 原图形数据 rgbrgbrgg排列
int dst_idx = dst_w * dst_h * k + j * dst_w + i;// 目标图像数据 bbbgggrrr排列
//dst_data[dst_idx] = (float)((unsigned char)rsz_data[src_idx]/* - 128*/)/* * 0.0078125*/; // 浮点类型数据 转换成0~1之间的数据
dst_data[dst_idx] = (unsigned char)rsz_data[src_idx];
}
}
}
cvReleaseImage(&src_img);
cvReleaseImage(&rsz_img);
// 2. bgr 平铺转 nv21
int channel_step = dst_h*dst_w;
int Yindex = 0, UVindex = 0;
unsigned char *dst_nv21_data_vu_p = dst_nv21_data + channel_step;
for (int i = 0; i < dst_h; i++)
{
for (int j = 0; j < dst_w; j++)
{
int channel_in_step = i*dst_h + j;
unsigned char *src_b_p = dst_data + channel_in_step;
unsigned char *src_g_p = dst_data + channel_in_step + channel_step;
unsigned char *src_r_p = dst_data + channel_in_step + channel_step * 2;
//计算Y的值
int Y = (77 * (*src_r_p) + 150 * (*src_g_p) + 29 * (*src_b_p)) >> 8;
dst_nv21_data[Yindex++] = (Y < 0) ? 0 : ((Y > 255) ? 255 : Y);
//计算U、V的值,进行2x2的采样
if (i % 2 == 0 && (j) % 2 == 0)
{
int U = ((-44 * (*src_r_p) - 87 * (*src_g_p) + 131 * (*src_b_p)) >> 8) + 128;
int V = ((131 * (*src_r_p) - 110 * (*src_g_p) - 21 * (*src_b_p)) >> 8) + 128;
dst_nv21_data_vu_p[UVindex++] = (V < 0) ? 0 : ((V > 255) ? 255 : V);
dst_nv21_data_vu_p[UVindex++] = (U < 0) ? 0 : ((U > 255) ? 255 : U);
}
}
}
FILE *file_out = fopen(save_file_path, "wb"); // 输出模型 可写 二进制格式
if (file_out == NULL)
{
printf("open file error :%s\n", save_file_path);
return 0;
}
fwrite(dst_nv21_data, 1, (dst_w * dst_h * 3 / 2), file_out);//保存图像数据
fclose(file_out);// 关闭文件
free(dst_data);
free(dst_nv21_data);
return 1;
}