最近遇到个需求,已有全景图和其中的人脸坐标,将人脸小图从全景图中抠出来,最开始使用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. [Tensorflow实战Google深度学习框架]笔记4

    本系列为Tensorflow实战Google深度学习框架知识笔记,仅为博主看书过程中觉得较为重要的知识点,简单摘要下来,内容较为零散,请见谅. 2017-11-06 [第五章] MNIST数字识别问题 ...

  2. 深入理解之 Android Handler

    深入理解之 Android Handler   一,相关概念 在Android中如果通过用户界面(如button)来来启动线程,然后再线程中的执行代码将状态信息输出到用户界面(如文本框),这时候就会抛 ...

  3. 剖析 GSM 加密机制以及位置更新的过程

    你有没有想过打开手机时会发生什么?它是如何以安全的方式与网络进行通信?几乎所有人都知道TCP / IP,并且可能许多人还是专家,但是谈到电信方面,很少有人知道它的内部原理. gsm中的消息结构是什么? ...

  4. Linux系统-tcpdump常用抓包命令

    主要语法 过滤主机/IP: tcpdump -i eth1 host 172.16.7.206 抓取所有经过网卡1,目的IP为172.16.7.206的网络数据 过滤端口:  tcpdump -i e ...

  5. 改善Python程序的条条建议

    1:引论   建议1.理解Pythonic概念—-详见Python中的<Python之禅> 建议2.编写Pythonic代码 避免不规范代码,比如只用大小写区分变量.使用容易混淆的变量名. ...

  6. 剑指Offer 33. 丑数 (其他)

    题目描述 把只包含质因子2.3和5的数称作丑数(Ugly Number).例如6.8都是丑数,但14不是,因为它包含质因子7. 习惯上我们把1当做是第一个丑数.求按从小到大的顺序的第N个丑数. 题目地 ...

  7. linux 内存使用情况详解

    一:首先是先登录 二:查看当前目录 命令:df -h 三:查看具体文件夹占用情况 命令:du --max-depth=1 -h  /data/ 或者:为了快算显示,同时也只是想查看目录整体占用大小 命 ...

  8. iOS tableView分割线高度自定义

    1.系统自带的集中分割线的形式 myTableView.separatorStyle=UITableViewCellSeparatorStyleNone;(这个是去掉所有分割线)可以通过这个来设置 2 ...

  9. php7之严格模式RFC

    首先需要开启严格模式: declare(strict_types = ); 严格模式下,形参和返回值可加限制.对返回值的限制需要在参数的()后面加上引号加类型限制即可,例: function demo ...

  10. java基础(3)java常用API

    1 ArrayList集合 01 创建 import java.util.ArrayList; /* 泛型:装在集合中的元素,全都是统一的一种类型.泛型必须是引用类型,不能是基本数据类型 */ pub ...