[libjpeg]读取一张raw图(NV12格式),双线性插值resiez+libjpeg压缩图像为jpg,并统计耗时.

面对图像较大而带宽不足的情况,往往需要对图像进行压缩,使其变小后得以方便传输。

本文使用libjpeg(非libjpeg-turbo)实现了对图像的压缩,并且使用双线性插值进行了resize。

1.encode_by_libjpeg.h

#include <iostream>
#include <fstream>
#include <cstring>

#include <jpeglib.h>
#include <setjmp.h>

int yuv420sp_to_jpeg_resize(const char * filename, unsigned char* pdata,int image_width,int image_height, int out_w,int out_h,int quality);
int read_Image_from_raw_by_iostream(const std::string filename, unsigned char **buffer);

2.encode_by_libjpeg.cpp

#include "encode_by_libjpeg.h"


int yuv420sp_to_jpeg_resize(const char * filename, unsigned char* pdata,int image_width,int image_height, int out_w,int out_h,int quality)
{   
    

    struct jpeg_compress_struct cinfo;  
    struct jpeg_error_mgr jerr;  
    cinfo.err = jpeg_std_error(&jerr);  
    jpeg_create_compress(&cinfo);  /*初始化*/
 
    FILE * outfile;    // target file  
    if ((outfile = fopen(filename, "wb")) == NULL) {  
        fprintf(stderr, "can't open %s\n", filename);  
        exit(1);  
    }  
    jpeg_stdio_dest(&cinfo, outfile);  /*指定输出文件*/
    
    
    /*设置压缩各项图片参数*/
    cinfo.image_width = out_w;  // image width and height, in pixels  
    cinfo.image_height = out_h;  
    cinfo.input_components = 3;    // # of color components per pixel  
    cinfo.in_color_space = JCS_YCbCr;  //colorspace of input image  
    jpeg_set_defaults(&cinfo);  
    /*设置压缩质量*/
    jpeg_set_quality(&cinfo, quality, TRUE );  
 
    //  
    //  cinfo.raw_data_in = TRUE;  
    cinfo.jpeg_color_space = JCS_YCbCr;  
    cinfo.comp_info[0].h_samp_factor = 2;  
    cinfo.comp_info[0].v_samp_factor = 2;  
    
    
    jpeg_start_compress(&cinfo, TRUE);  
 
    JSAMPROW row_pointer[1];
 
    unsigned char *yuvbuf;
    if((yuvbuf=(unsigned char *)malloc(out_w*3))!=NULL)
        memset(yuvbuf,0,out_w*3);
 
    unsigned char *ybase,*ubase;
    ybase=pdata;
    ubase=pdata+image_width*image_height;  
    int j=0;

  
    //dest[dx+dy*dest_width] = src[(dx*src_width/dest_width)+(dy*src_height/dest_height)*src_width]
    while (cinfo.next_scanline < out_h) 
    {
        int idx=0;
        for(int i=0;i<out_w;i++)
        { 
            float srcX = i * ((float)(image_width - 1) / (out_w - 1));
		    float srcY = j * ((float)(image_height - 1) / (out_h - 1));
         
            
		// 计算取图像坐标
		int fx0 = srcX;
		int fy0 = srcY;
		int fx1 = srcX > fx0 ? fx0 + 1 : fx0;
		int fy1 = srcY > fy0 ? fy0 + 1 : fy0;

		// 计算取像素比例
		float xProportion = srcX - fx0;
		float yProportion = srcY - fy0;

		// 四个输入坐标
		int idx_in_y_00 = fy0 * image_width + fx0;
		int idx_in_uv_00 = fy0 / 2 * image_width + fx0;

		int idx_in_y_10 = fy1 * image_width + fx0;
		int idx_in_uv_10 = fy1 / 2 * image_width + fx0;

		int idx_in_y_01 = fy0 * image_width + fx1;
		int idx_in_uv_01 = fy0 / 2 * image_width + fx1;

		int idx_in_y_11 = fy1 * image_width + fx1;
		int idx_in_uv_11 = fy1 / 2 * image_width + fx1;

		// Y
		yuvbuf[idx++] =
			ybase[idx_in_y_00] * (1 - xProportion) * (1 - yProportion) +
			ybase[idx_in_y_10] * xProportion * (1 - yProportion) +
			ybase[idx_in_y_01] * (1 - xProportion) * yProportion +
			ybase[idx_in_y_11] * xProportion * yProportion;

		// U
		yuvbuf[idx++] =
			ubase[fx0 % 2 == 0 ? idx_in_uv_00 : idx_in_uv_00 - 1] * (1 - xProportion) * (1 - yProportion) +
			ubase[fx0 % 2 == 0 ? idx_in_uv_10 : idx_in_uv_10 - 1] * xProportion * (1 - yProportion) +
			ubase[fx1 % 2 == 0 ? idx_in_uv_01 : idx_in_uv_01 - 1] * (1 - xProportion) * yProportion +
			ubase[fx1 % 2 == 0 ? idx_in_uv_11 : idx_in_uv_11 - 1] * xProportion * yProportion;

		// V
		yuvbuf[idx++] =
			ubase[fx0 % 2 == 0 ? idx_in_uv_00 + 1 : idx_in_uv_00] * (1 - xProportion) * (1 - yProportion) +
			ubase[fx0 % 2 == 0 ? idx_in_uv_10 + 1 : idx_in_uv_10] * xProportion * (1 - yProportion) +
			ubase[fx1 % 2 == 0 ? idx_in_uv_01 + 1 : idx_in_uv_01] * (1 - xProportion) * yProportion +
			ubase[fx1 % 2 == 0 ? idx_in_uv_11 + 1 : idx_in_uv_11] * xProportion * yProportion;
	

        }
        row_pointer[0] = yuvbuf;
        /*逐行扫描压缩写入文件*/
        jpeg_write_scanlines(&cinfo, row_pointer, 1);
        j++;
    }

    /*完成压缩*/
    jpeg_finish_compress(&cinfo);  
    jpeg_destroy_compress(&cinfo);  
    fclose(outfile);  
    return 0;  
}

int read_Image_from_raw_by_iostream(const std::string  filename, unsigned char **buffer)
{
	   // open raw data
    
    std::ifstream fin;
    // 注意,这里要指定binary读取模式
    fin.open(filename,  std::ios::binary);
    if (!fin) {
        std::cerr << "open failed: " << filename << std::endl;
    }
	// seek函数会把标记移动到输入流的结尾
    fin.seekg(0, fin.end);
    // tell会告知整个输入流(从开头到标记)的字节数量
    int length = fin.tellg();
   	// 再把标记移动到流的开始位置
    fin.seekg(0, fin.beg);
    //std::cout << "file length: " << length << std::endl;
    
    // load buffer
    char* temp_buf = new char [length];
    // read函数读取(拷贝)流中的length各字节到buffer
    fin.read(temp_buf, length);
	
	*buffer=reinterpret_cast<u_char *>(temp_buf);
    return 0;

}

3.main.cpp

#include "encode_by_libjpeg.h"
#include <iostream>

#include <algorithm>
#include <chrono>

struct Rawimage_t {
	size_t input_w, input_h;
	unsigned char *yuv420sp;
};



int main()
{
    
    Rawimage_t image;

    int input_width=3840 ;
    int input_height=2176;
    int output_width=1920 ;
    int output_height=1088;
  
    read_Image_from_raw_by_iostream("test.raw", &image.yuv420sp);

	auto start = std::chrono::high_resolution_clock::now();
        
    yuv420sp_to_jpeg_resize("output.jpg",image.yuv420sp,input_width,
                              input_height,output_width,output_height, 60);
	auto stop = std::chrono::high_resolution_clock::now();
   	auto duration = std::chrono::duration_cast<std::chrono::microseconds>(stop - start);
	std::cout << "Time taken: " << duration.count() /1000.0<< " ms" << std::endl;	
			
    /* Free image memory */
	free(image.yuv420sp);
	
    return 0;
}

4.Makefile

demo : main.cpp encode_by_libjpeg.cpp
	g++ main.cpp encode_by_libjpeg.cpp  -I/opt/libjpeg-turbo/include -L/opt/libjpeg-turbo/lib64 -ljpeg   

好的,你可以参考以下步骤: 1. 下载libjpeg库文件,并将其加入到你的Android项目中。 2. 在你的C/C++代码中,包含libjpeg的头文件:#include "jpeglib.h" 3. 定义一个结构体,用于存储压缩后的图像数据: ```c++ struct jpeg_compress_struct cinfo; struct jpeg_error_mgr jerr; cinfo.err = jpeg_std_error(&jerr); jpeg_create_compress(&cinfo); ``` 4. 设置压缩参数: ```c++ cinfo.image_width = width; // 设置图像宽度 cinfo.image_height = height; // 设置图像高度 cinfo.input_components = 1; // 设置图像颜色分量数 cinfo.in_color_space = JCS_GRAYSCALE; // 设置图像颜色空间为灰度 jpeg_set_defaults(&cinfo); jpeg_set_quality(&cinfo, quality, TRUE); // 设置压缩质量 ``` 5. 指定输出文件或者输出缓冲区: ```c++ FILE *outfile; // 输出到文件 outfile = fopen(outfilename, "wb"); jpeg_stdio_dest(&cinfo, outfile); // 或者输出到缓冲区 unsigned char *outbuffer; outbuffer = (unsigned char *)malloc(buffer_size); jpeg_mem_dest(&cinfo, &outbuffer, &buffer_size); ``` 6. 开始压缩: ```c++ jpeg_start_compress(&cinfo, TRUE); JSAMPROW row_pointer[1]; while (cinfo.next_scanline < cinfo.image_height) { row_pointer[0] = &image_data[cinfo.next_scanline * cinfo.image_width]; jpeg_write_scanlines(&cinfo, row_pointer, 1); } jpeg_finish_compress(&cinfo); ``` 7. 释放资源: ```c++ jpeg_destroy_compress(&cinfo); fclose(outfile); // 如果输出到文件 free(outbuffer); // 如果输出到缓冲区 ``` 这样就可以使用libjpeg库对RAW8图像数据进行压缩了。需要注意的是,压缩后的图像数据需要进行压缩才能还原成原始图像数据。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值