最近遇到个需求,已有全景图和其中的人脸坐标,将人脸小图从全景图中抠出来,最开始使用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的更多相关文章

  1. jquery中定义数组并给数组赋值后转为json格式为[]问题的解决

    一.问题描述:jquery定义一个空数组,并赋值,结果转为json格式后打印值为空 我原本是这样写的,但是show_data值一直为[] var export_data = [];export_dat ...

  2. 成 功 的 背 后 !( 致给所有IT人员)

    转载了这篇文章,希望能对自己和看到这篇博客的人有所激励. 成功的背后,有着许多不为人知的故事,而正是这些夹杂着泪水和汗水的过去,才成就了一个个走向成功的普通人. ------------------- ...

  3. PS教程1000例

    http://www.missyuan.com/thread-446934-1-1.html Photoshop绘制逼真头发发丝效果http://www.missyuan.com/thread-446 ...

  4. 微信小程序音乐播放器

    写在前面 1.入门几天小白的作品,希望为您有帮助,有好的意见或简易烦请赐教 2.微信小程序审核音乐类别已经下架,想要发布选题需慎重.附一个参考链接,感谢https://www.hishop.com.c ...

  5. AES加密

    package com.edu.hpu; import java.math.BigInteger; import java.security.MessageDigest; import java.se ...

  6. 解决IE8下不兼容rgba()的解决办法

    rgba()是css3的新属性,所以IE8及以下浏览器不兼容,这怎么办呢?终于我找到了解决办法. 解决办法 我们先来解释以下rgba rgba: rgba的含义,r代表red,g代表green,b代表 ...

  7. C#中POST数据和接收的几种方式(抛砖引玉)

    POST方式提交数据,一种众所周知的方式: html页面中使用form表单提交,接收方式,使用Request.Form[""]或Request.QueryString[" ...

  8. ie6,ie7,ie8 css bug兼容解决方法

    IE浏览器以不支持大量的css 属性出名,同时也因其支持的css属性中存在大量bug. 这里收集了好多的bug以及其解决的办法,都在这个文章里面记录下来了!希望以后解决类似问题的时候能够快速解决,也希 ...

  9. 案例1.用Ajax实现用户名的校验

    用Ajax实现用户名的校验 java的验证类 public class UserDao { public boolean checkUserName(String name) { //这里的name是 ...

随机推荐

  1. 201671010142 <java程序设计>初次学习心得与感悟

    从开始对JDK的配置就遇到了问题,从这点就可以知道自己知识的薄弱.又知道了在控制台下一些常用命令的掌握.对知识的理解挺艰难,比如遇到一个新的问题就不知道该从哪里入手,有时候还不知道到底问题是啥.接受能 ...

  2. inventory file 与hosts patterns (ansible 机器清单 与 主机匹配模式)

    Ansible配置: ansible有两个核心配置文件: ansible.cfg 配置文件和Inventory配置文件 Ansible.cfg配置文件 Inventory机器列表配置 这里介绍Inve ...

  3. 项目中Java Resources有红叉,其它没有,解决办法

    说起这个这个地方,我课改了好久 起初,我把原先项目的JDK版本改了,右击项目Build Path,然后换掉里面的JRE,没用, 然后右击项目,点击properties,找到在Project Facet ...

  4. makeObjectsPerformSelector对数组中的对象发送消息执行对象中方法

    - (void)makeObjectsPerformSelector:(SEL)aSelector; - (void)makeObjectsPerformSelector:(SEL)aSelector ...

  5. mysql oracle 数据库备份

    mysql 备份与还原 转载:https://blog.csdn.net/win_turn/article/details/60880990 备份数据库 数据库名叫dddd  mysqldump -u ...

  6. python实现简单的定时任务

    1.首先安装 schedule 模块 命令行安装 pip install schedule pyCharm编辑器安装 File->setting->project:youProject-& ...

  7. jq实时监测输入框内容改变

    $(document) .on('input propertychange','#telInput',function (e) { if (e.type === "input" | ...

  8. Linux源码安装软件

    Linux环境下 源码编译安装软件 ==== 1. 下载,步骤略 ==== 2. 验证,部分官方下载同时提供签名,MD5,sha1,sha256等校验信息. $ gpg --verify gnupg- ...

  9. JSON的一些小结

    一.js中 1.json字符串转json对象 var json = $.parseJSON(" {'1':'hello'},{'2':'word'} "); for(var i i ...

  10. react 点击空白处隐藏弹出层

    点击空白处隐藏弹出层的原理是:在 document 上绑定事件来隐藏弹出层,这样点击任何元素的时候都会冒泡到 document 上,都会执行隐藏弹出层的功能.然后我们在不需要隐藏弹出层的元素上阻止冒泡 ...