jpg转yuv420抠图后转为jpg
最近遇到个需求,已有全景图和其中的人脸坐标,将人脸小图从全景图中抠出来,最开始使用libjpeg,奈何使用libjpeg将jpg转为yuv420的资料实在少,libjpeg自身的readme和example也是异常简陋,只介绍了常用函数,却没有具体的yuv数据计算方法,搞了两天最后jpg解码yuv成功后,再切图后继续转为jpg后将数据写到文件发现问题,小图始终没有数据。
无奈只能copy代码中原有的一份算法解码库,进行类似操作后,小图转为jpg后还是空的,求助算法大佬后发现自己一开始就给自己写了个大bug,就是小图yuv转为jpg后是存储在malloc的一段内存里的,类型为char*,一开始为了数据copy方便,就直接将jpg的指针赋给了std::string,再利用string中数据写到文件里,导致文件一直是空的,其实小图的jpg数据已经成功的转化了,只是自己没理解char*指针和string的区别,以为所有指针都可以直接赋给std::string,其实char*型指针里如果保存的是类似图片数据这种不是标准的字符串的话,是很容易出现数据被截断的情况的,如果实在要赋值的话,需要加上需要复制的长度才行,实在汗颜,期间遇到很多指针操作,如三级指针、指针数组、指针分配内存(要使用指针必须分配内存或者指向已分配内存的地址,还要注意不要提前释放掉还在使用的指针指向的内存)、指针转string(指针若指向的非标准字符串则赋给std::string时需要加上需要复制的长度),char*和unsigned char*的区别(例如16进制0xffffffff存储在char*里表示为-1,存储在unsigned char*里表示为0xff),感觉自己对C的指针了解还是太少。
除此之外,我发现一个更深层次的问题就是自己遇到新的东西不愿意去思考和了解,固步自封,只知道百度现成代码复制粘贴,也不去思考复制过来的代码是什么原理,适不适用现有业务,也不知道看官方的例子(虽然libjpeg官方的例子实在是有点垃圾,但是最好还是要先看下官方文档),也让我了解到需要学习的地方还有很多,基础知识还是相当的薄弱,还需要不断学习。
说了这么多,还是把这次研究了好几天的jpg转yuv420p,yuv420p转jpg的代码分享出来下,供大家参考(参考博文:https://www.cnblogs.com/zhq-blog/p/8858293.html):
#include <windows.h>
#include <iostream>
#include <vector>
#include <memory>
#include <jpeglib.h> #define NEW_BUFFER(param, len) if(!param)\
{ param = new unsigned char[len];}\
else { delete param; param = new unsigned char[len];}; using namespace std; unsigned char** yuvptr_[];
std::vector< std::vector<unsigned char*> > yuvbuf_();
unsigned char* m_pYbuffer = NULL;
unsigned char* m_pUbuffer = NULL;
unsigned char* m_pVbuffer = NULL; std::string jpg_to_yuv420p(char* pBuffer, int nSize, int &uPicWidth, int &uPicHeight)
{
struct jpeg_error_mgr e_;
jpeg_decompress_struct info_;
info_.err = jpeg_std_error(&e_);
jpeg_create_decompress(&info_);
jpeg_mem_src(&info_, (unsigned char*)pBuffer, nSize); //// 指定图片在内存的地址及大小
jpeg_read_header(&info_, );
info_.out_color_space = JCS_YCbCr;
info_.raw_data_out = ;
info_.do_fancy_upsampling = FALSE;
jpeg_start_decompress(&info_); for (int i = ; i < ; ++i)
{
yuvbuf_[i].resize(info_.output_width);
yuvptr_[i] = &yuvbuf_[i][];
} int nLen = info_.output_width * info_.output_height; NEW_BUFFER(m_pYbuffer, nLen);
NEW_BUFFER(m_pUbuffer, nLen);
NEW_BUFFER(m_pVbuffer, nLen); unsigned char* row = m_pYbuffer;
yuvptr_[][] = row;
for (int i = ; i < info_.output_height; ++i, row += info_.output_width)
{
yuvptr_[][i] = row; //y 分量空间初始化
} row = m_pUbuffer;
for (int i = ; i < info_.output_height; i += , row += info_.output_width / )
{
yuvptr_[][i / ] = row; //u 分量初始化 } row = m_pVbuffer;
for (int i = ; i < info_.output_height; i += , row += info_.output_width / )
{
yuvptr_[][i / ] = row; //v 分量初始化
} for (int i = ; i < info_.output_height; i += )
{
int nRows = ;
if ((info_.output_height) < (i + ))
{
nRows = info_.output_height - i;
}
jpeg_read_raw_data(&info_, yuvptr_, nRows);
yuvptr_[] += ;
yuvptr_[] += ;
yuvptr_[] += ;
}
uPicWidth = info_.image_width;
uPicHeight = info_.image_height; std::string Y((char*)yuvbuf_[][], uPicWidth*uPicHeight); std::string U((char*)yuvbuf_[][], uPicWidth*uPicHeight / ); std::string V((char*)yuvbuf_[][], uPicWidth*uPicHeight / ); std::string YUV = Y + U + V; cout << YUV.size() << endl; jpeg_finish_decompress(&info_);
jpeg_destroy_decompress(&info_); return YUV;
} int yuv420p_to_jpeg(unsigned char* pdata, int image_width, int image_height, int quality)
{
if (image_width == || image_height == ) {
cout << "err param\n";
return ;
}
struct jpeg_compress_struct cinfo;
struct jpeg_error_mgr jerr;
cinfo.err = jpeg_std_error(&jerr);
jpeg_create_compress(&cinfo);
unsigned char *outbuffer;
unsigned long size = ;
jpeg_mem_dest(&cinfo, &outbuffer, &size); cinfo.image_width = image_width; // image width and height, in pixels
cinfo.image_height = image_height;
cinfo.input_components = ; // # 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[].h_samp_factor = ;
cinfo.comp_info[].v_samp_factor = ;
/////////////////////////
jpeg_start_compress(&cinfo, TRUE); JSAMPROW row_pointer[]; unsigned char *yuvbuf;
if ((yuvbuf = (unsigned char *)malloc(image_width * )) != NULL)
memset(yuvbuf, , image_width * ); unsigned char *ybase, *ubase, *vbase;
ybase = pdata;
ubase = pdata + image_width*image_height;
vbase = ubase + image_width*image_height / ;
int j = ;
while (cinfo.next_scanline < cinfo.image_height)
{
int idx = ;
for (int i = ; i < image_width; i++)
{
yuvbuf[idx++] = ybase[i + j * image_width];
yuvbuf[idx++] = ubase[j / * image_width/ + (i / )];
yuvbuf[idx++] = vbase[j / * image_width/ + (i / )];
}
row_pointer[] = yuvbuf;
jpeg_write_scanlines(&cinfo, row_pointer, );
j++;
}
jpeg_finish_compress(&cinfo);
jpeg_destroy_compress(&cinfo);
if (yuvbuf != NULL)
{
free(yuvbuf);
} FILE *fp = NULL;
errno_t err;
err = fopen_s(&fp, "C:/Users/chenwenjun/Desktop/ok.jpg", "wb");
if (fp) {
fwrite(outbuffer, size, , fp);
fclose(fp);
}
else {
cout << "nok\n";
} free(outbuffer);
} int main()
{
std::shared_ptr<char> PicData = NULL; //get pic data
FILE* fp = NULL;
errno_t err;
err = fopen_s(&fp, "C:/Users/chenwenjun/Desktop/test.jpg", "rb");
if (!err) {
PicData.reset(new char[ * * ]);
fread((void*)PicData.get(), * * , , fp);
fclose(fp);
}
else {
cout << "nok\n";
} //jpg -> yuv
int uPicWidth = , uPicHeight = ;
std::string YUVData = jpg_to_yuv420p(PicData.get(), * * , uPicWidth, uPicHeight); //yuv -> jpg
yuv420p_to_jpeg((unsigned char*)const_cast<char*>(YUVData.c_str()), uPicWidth, uPicHeight, ); Sleep(); return ;
}
jpg转yuv420抠图后转为jpg的更多相关文章
- jquery中定义数组并给数组赋值后转为json格式为[]问题的解决
一.问题描述:jquery定义一个空数组,并赋值,结果转为json格式后打印值为空 我原本是这样写的,但是show_data值一直为[] var export_data = [];export_dat ...
- 成 功 的 背 后 !( 致给所有IT人员)
转载了这篇文章,希望能对自己和看到这篇博客的人有所激励. 成功的背后,有着许多不为人知的故事,而正是这些夹杂着泪水和汗水的过去,才成就了一个个走向成功的普通人. ------------------- ...
- PS教程1000例
http://www.missyuan.com/thread-446934-1-1.html Photoshop绘制逼真头发发丝效果http://www.missyuan.com/thread-446 ...
- 微信小程序音乐播放器
写在前面 1.入门几天小白的作品,希望为您有帮助,有好的意见或简易烦请赐教 2.微信小程序审核音乐类别已经下架,想要发布选题需慎重.附一个参考链接,感谢https://www.hishop.com.c ...
- AES加密
package com.edu.hpu; import java.math.BigInteger; import java.security.MessageDigest; import java.se ...
- 解决IE8下不兼容rgba()的解决办法
rgba()是css3的新属性,所以IE8及以下浏览器不兼容,这怎么办呢?终于我找到了解决办法. 解决办法 我们先来解释以下rgba rgba: rgba的含义,r代表red,g代表green,b代表 ...
- C#中POST数据和接收的几种方式(抛砖引玉)
POST方式提交数据,一种众所周知的方式: html页面中使用form表单提交,接收方式,使用Request.Form[""]或Request.QueryString[" ...
- ie6,ie7,ie8 css bug兼容解决方法
IE浏览器以不支持大量的css 属性出名,同时也因其支持的css属性中存在大量bug. 这里收集了好多的bug以及其解决的办法,都在这个文章里面记录下来了!希望以后解决类似问题的时候能够快速解决,也希 ...
- 案例1.用Ajax实现用户名的校验
用Ajax实现用户名的校验 java的验证类 public class UserDao { public boolean checkUserName(String name) { //这里的name是 ...
随机推荐
- python笔记8-列表list操作、多维数组
#!/usr/bin/python #python里面有个这个话,代表在linux下运行的时候#去哪个目录下找python的解释器,在windows上运行不用写# coding:utf-8# __*_ ...
- SharePoint Framework Extensions GA Release
博客地址:http://blog.csdn.net/FoxDave SharePoint Framework Extensions GA版本已经发布了,介于最近个人工作的变动调整,还没时间好好了解一下 ...
- [Version Control]—— Git如何使用
Git是什么? Git是目前世界上最先进的分布式版本控制系统. 它没有中央服务器的,每个人的电脑就是一个完整的版本库,这样,工作的时候就不需要联网了,因为版本都是在自己的电脑上.既然每个人的电脑都有一 ...
- ant通配符
ANT通配符有三种: 通配符 说明 ? 匹配任何单字符 * 匹配0或者任意数量的字符 ** 匹配0或者更多的目录 例子: URL路径 说明 /app/*.x 匹配(Matches)所有在app路径下的 ...
- ecmall 入口文件解析 引入了什么
每一个框架都有自动载入的工具库,搜了半天也没搜到相关介绍,就自己看入口文件琢磨了一下, <?php define('ROOT_PATH', dirname(__FILE__)); //定义项目根 ...
- j教你如何用erlang-tuple
元组是用来保存一组数据元素的复合数据类型,其中数据元素是要求为erlang的数据类型,单不一定要是相同的类型,元组使用封闭的花括号{}来定义,里面的元素有逗号隔开. 例如: 1> {1,2,3} ...
- DG_数据文件转换参数测试
本篇博客流程图: 一.测试需求及参数说明 二.测试环境进行相关测试 三.问题总结 一.测试需求及参数说明 1.1测试需求说明 DG切换 切换前,数据库版本12.2.0.1,主库rac两节点,备一rac ...
- JavaBasic_12
类 抽象:对象的共性 类:产生对象的模板(对于属性来讲,类规定有没有属性以及属性类型,具体的属性值因对象的不同而不同) 数据类型:数据集及基于这个数据集的操作 类:我们自定义类型(定义成员变量,基于数 ...
- BBS项目详解(forms快速创建登陆页面,登陆验证、通过阅读器进行头像上传的预览、内存管理器)
BBS项目涉及的知识点 django中知识点 钩子函数(局部钩子和全局钩子) 1.局部钩子就是用来做合法性校验,比如用户名有没有被使用等 2.全局的就是用来做对比校验,比如两次输入的密码是否一致 3. ...
- Spring的学习和源码的学习
PS:Spring中有各种的Templeate,比如jdncTemplate,主要是为了避免各种模板的代码,抽象出来的 PS: @Configration.@Bean是用来替代xml那种解析方式 PS ...