最近遇到个需求,已有全景图和其中的人脸坐标,将人脸小图从全景图中抠出来,最开始使用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. Android : Android Studio 更新至gradle 4.10.1后Variants API变化

    同步警告: WARNING: API 'variantOutput.getPackageApplication()' is obsolete and has been replaced with 'v ...

  2. ganglia监控架构

    1.我们知道ganglia是C/S结构的,我们熟知的就是一台ganglia server,很多slave.这种结构有什么问题? 1)如果ganglia server出现问题,我们就无法监控到datan ...

  3. java面向对象编程(五)--四大特征之抽象、封装

    1.抽象 我们在前面去定义一个类时候,实际上就是把一类事物的共有的属性和行为提取出来,形成一个物理模型(模版).这种研究问题的方法称为抽象. 2.封装 封装就是把抽象出来的数据和对数据的操作封装在一起 ...

  4. idea取消参数名称(形参名)提示

    idea取消参数名称(形参名)提示 IDEA会自动显示形式参数的变量名称,这在一开始使用时感觉很方便,友好.有时候也会显得排版很乱,下面是取消自动显示形式参数名称的方式 取消前是这个样子. “File ...

  5. Xcodebuild ipa shell

    命令行下打包iOS App工程: #!/bin/sh # # How To Build ? #http://www.jianshu.com/p/3f43370437d2 #http://www.jia ...

  6. 【EMV L2】SDA静态数据认证处理流程

    [静态数据认证] 静态数据认证处理过程中,卡片没有执行任何处理,终端执行的处理流程:1.认证中心公钥的获取终端使用卡片上的认证中心公钥索引(PKI)[TAG:8F,Certification Auth ...

  7. docker下运行labview2010

    前言 本人笔记本用kali,因课程需要,要在Linux下运行Labview,找到了2010的iso,但只支持rehat系列的发行版,用rpm转化deb的方案不可行,尝试了在virtualbox下运行w ...

  8. Redis占硬盘空间

    转载自:http://blog.csdn.net/qq285744011/article/details/51002409 [问题的原因] Windows版Redis启动后,会在C盘自动创建一个很大的 ...

  9. H5入门须知

    ---恢复内容开始--- 首先,让我们来了解一下H5是做什么的,H5全称为“超文本标记语言”.是对网页进行编辑的技术.H5运用Hbulider进行网页编辑.网页可以分为三部分分别是title(主题)u ...

  10. selenium 安装

    selenium 安装 一.chromerdriver 1.浏览器版本 1)检查谷歌浏览器版本 打开chrome输入 "chrome://version/"查看版本,如图所示: 2 ...