图像转YUV处理

版权声明:www.gudianxiaoshuo.com (古典小说网) 今日头条号: 古典古韵古典小说、讨厌编程 https://blog.csdn.net/shuilan0066/article/details/87881329

使用GDI+来处理图像,

初始工作

1)头文件

#include <GdiPlus.h>
#pragma comment(lib, "GdiPlus.lib")
using namespace Gdiplus;

2)定义变量

GdiplusStartupInput    m_Gdistart; 
ULONG_PTR    m_GdiplusToken;

3)
//起止位置
GdiplusStartup(&m_GdiplusToken, &m_Gdistart, NULL);


//销毁位置
Gdiplus::GdiplusShutdown(m_pGdiToken)

不过我在云信duilib中,只找到#include <GdiPlus.h>  ,估计其它的工作都封装起来了。

 


一 :分解说明

1、加载图像

   将本地图像,加载成GID+ Bitmap, 将此Bitmap数据转换成YUV数据

1)GDI+ 加载图像


Bitmap::Bitmap(
    IN const WCHAR *filename, 
    IN BOOL useEmbeddedColorManagement
    )
{
    GpBitmap *bitmap = NULL;

    if(useEmbeddedColorManagement) 
    {
        lastResult = DllExports::GdipCreateBitmapFromFileICM(filename, &bitmap);
    }
    else
    {
        lastResult = DllExports::GdipCreateBitmapFromFile(filename, &bitmap);
    }

    SetNativeImage(bitmap);
}

2) 加载图像 保存在共享指针变量中


std::shared_ptr<Gdiplus::Bitmap> src_image_;

//加载图像
src_image_.reset(new Gdiplus::Bitmap(path.c_str()));

//判断加载是否成功

status = src_image_->GetLastStatus();
	ASSERT(status == Gdiplus::Ok);
	if (status != Gdiplus::Ok) {
		return false;
	}


2、图像字节数据保存

     将数据保存在std::string data_中

struct ImageFrame {
	std::string data_;
	int height_;
	int width_;
	int time_;
	bool alpha_;
	int index_;
	ImageFrame()
	{
		height_ = 0;
		width_ = 0;
		time_ = 100;
		alpha_ = false;
		index_ = 0;
	}
};

有的图像格式 比如gif tif等有好几帧, 这些图像帧也保存起来

std::vector<ImageFrame> image_list_;

这样就涉及到获取图像多少帧,帧间隔,获得某帧视频数据问题,不过这些gdi+都可以处理

3、图像帧处理

1) 获得多少帧

	UINT nCount = src_image_->GetFrameDimensionsCount();
	std::unique_ptr<GUID[]> pDimensionIDs(new GUID[nCount]);
	src_image_->GetFrameDimensionsList(pDimensionIDs.get(), nCount);
	int iFrameCount = src_image_->GetFrameCount(&pDimensionIDs.get()[0]);
	Gdiplus::PropertyItem* propertyItem = nullptr;
	if (iFrameCount > 1) {
		int iSize = src_image_->GetPropertyItemSize(PropertyTagFrameDelay);
		/*Gdiplus::PropertyItem* */
		propertyItem = (Gdiplus::PropertyItem*) malloc(iSize);
		status = src_image_->GetPropertyItem(PropertyTagFrameDelay, iSize, propertyItem);
		ASSERT(status == Gdiplus::Ok);
		if (status != Gdiplus::Ok) {
			return false;
		}
	}

2)获得帧间隔

	time_all_ = 0;
	for (int i = 0; i < iFrameCount; i++) {
		ImageFrame image_frame;
		int interval = 100;
		if (propertyItem)
		{
			int interval = ((long*)(propertyItem->value))[i] * 10;
			if (interval < 30) {
				interval = 100;
			}
			else if (interval < 50)
			{
				interval = 50;
			}
		}
		time_all_ += interval;
		image_frame.time_ = time_all_;

		if (CheckImageFrame(i, &image_frame, 0,0))
		{
			image_list_.push_back(image_frame);
		}
	}

3) 将每帧的数据保存在ImageFrame中

  •   选择图像中某一帧
	if (src_image_ == nullptr)
	{
		return false;
	}
	Gdiplus::Status status;
	status = src_image_->SelectActiveFrame(&Gdiplus::FrameDimensionTime, index);
	ASSERT(status == Gdiplus::Ok);
	if (status != Gdiplus::Ok) {
		return false;
	}
  • 获得此帧对应的Bitmap
	Gdiplus::Bitmap* bitmap = nullptr;
	bool creat_bitmap = false;
	if (src_height == height && src_width == width)
	{

		bitmap = src_image_.get();
	}

   如果,所要的图像大小和原图大小不一样,则创建一个新Bitmap, 然后在此新 Bitmap上绘图

	Gdiplus::Bitmap* bitmap = nullptr;
	bool creat_bitmap = false;
	if (src_height == height && src_width == width)
	{

		bitmap = src_image_.get();
	}
	else
	{
		bitmap = new Gdiplus::Bitmap(width, height, PixelFormat32bppARGB);
		Gdiplus::Graphics g(bitmap);

		//Gdiplus::SolidBrush brush(Gdiplus::Color(250, 0, 0, 0));
		//g.FillRectangle(&brush, 0, 0, width, height);

		g.DrawImage(src_image_.get(),  width/4, height/4,width/2,height/2);
		//g.DrawImage(src_image_.get(), 0,0, width, height );
		creat_bitmap = true;

		//Gdiplus::Pen pen(Gdiplus::Color(255, 255, 111, 0), 300);
		//Gdiplus::Rect rc(0, 0, width, height);
		//g.DrawRectangle(&pen, rc);
		//g.DrawImage(src_image_.get(), Gdiplus::Rect(0, 0, width, height), 0, 0, src_width, src_height, Gdiplus::UnitPixel);
	}



。。。。

。。。。

。。。。

在处理完毕后,如果是创建的Bitmap,则将其释放掉

	if (creat_bitmap)
	{
		delete bitmap;
		bitmap = nullptr;
	}
  • 获得Bitmap中的数据
class BitmapData
{
public:
    UINT Width;
    UINT Height;
    INT Stride;
    PixelFormat PixelFormat;
    VOID* Scan0;
    UINT_PTR Reserved;
};


 //图像数据保存在data.Scan0中

    Gdiplus::BitmapData data;
	
    Gdiplus::Rect rect(0, 0, width, height);

	int type = bitmap->GetPixelFormat();

//	ASSERT(type == PixelFormat32bppARGB);
	bitmap->LockBits(&rect, Gdiplus::ImageLockModeRead | Gdiplus::ImageLockModeWrite, PixelFormat32bppARGB, &data);

	int byte_width = data.Stride;
	image_frame->width_ = width;
	image_frame->height_ = height;
	image_frame->index_ = index;
	image_frame->alpha_ = CopyImageData((const char*)data.Scan0, data.Stride, image_frame->data_, width, height);
	bitmap->UnlockBits(&data);
  • ARGB数据 转YUV420数据
bool YuvImage::CopyImageData(const char* src, int byte_width, std::string& dest, int width, int height)
{
	bool alpha = false;
	int wxh = width * height;
	dest.clear();
	dest.append(wxh * 3, (char)0);
	uint8_t* des_y = (uint8_t*)dest.c_str();
	uint8_t* des_u = des_y + wxh * 2;
	uint8_t* des_v = des_u + wxh / 2;
	const uint8_t* src_argb = (const uint8_t*)src;
	libyuv::ARGBToI420(src_argb, byte_width,
		des_y, width * 2,
		des_u, width,
		des_v, width,
		width, height);
	uint8_t* a1 = (uint8_t*)src + 3;
	uint8_t* des_ya = des_y + width;
	uint8_t* des_ua = des_u + width / 2;
	uint8_t* des_va = des_v + width / 2;
	for (int i = 0; i < height / 2; ++i)
	{
		uint8_t* a2 = a1 + byte_width;
		uint8_t* des_ya2 = des_ya + width * 2;
		for (int j = 0; j < width / 2; ++j)
		{
			int y1 = *a1;
			a1 += 4;
			*(des_ya++) = y1;
			int y2 = *a1;
			a1 += 4;
			*(des_ya++) = y2;
			int y3 = *a2;
			a2 += 4;
			*(des_ya2++) = y3;
			int y4 = *a2;
			a2 += 4;
			*(des_ya2++) = y4;
			uint8_t a_uv = (y1 + y2 + y3 + y4) / 4;
			*(des_ua++) = a_uv;
			*(des_va++) = a_uv;
			if (a_uv != 255)
			{
				alpha = true;
			}
		}
		a1 += byte_width;
		des_ya += width * 3;
		des_ua += width / 2;
		des_va += width / 2;
	}
	return alpha;
}

4 图像加载 并转化成YUV数据  封装成单独的YuvImage类处理

class YuvImage
{
public:
	YuvImage();
	~YuvImage();
	bool LoadImage(std::wstring path);
	bool AddText(const std::wstring& text, int width, int height, DWORD color, int iFont, UINT uStyle, BYTE uFade, bool bLineLimit);
	ImageFrame* GetImageFrame(int index, int width = -1, int height = -1);
	ImageFrame* GetImageFrameEx(int64_t time, int width = -1, int height = -1);

	ImageFrame* GetOriImageFrame(int index);


private:
	bool CheckImageFrame(int index, ImageFrame* image_frame, int width, int height);
	bool CopyImageData(const char* src, int byte_width, std::string& dest, int width, int height);
	bool DrawText(int index, int width, int height, DWORD color, int iFont, UINT uStyle, BYTE uFade, bool bLineLimit);
private:
	std::vector<ImageFrame> image_list_;
	std::shared_ptr<Gdiplus::Bitmap> src_image_;
	int time_all_;
	std::wstring image_path_;
	std::wstring text_;
	int64_t time_start_;
};

二  具体使用

std::vector<YuvImage> yuv_image_list_;
void ScreenCaptureTool::SetTextLogo(std::wstring text)
{
	nbase::NAutoLock auto_lock(&lock_);
	yuv_image_list_.clear();



	std::wstring dir = QPath::GetAppPath();
	std::wstring logoPath, logo2Path;

	logoPath = dir;
	logo2Path = dir;
	logoPath.append(L"logo.png");
	logo2Path.append(L"logo2.png");


	if (::PathFileExists(logoPath.c_str()))
	{
		YuvImage image0;
		image0.LoadImage(logoPath.c_str());
		yuv_image_list_.push_back(image0);
	}

	if (::PathFileExists(logo2Path.c_str()))
	{
		YuvImage image0;
		image0.LoadImage(logo2Path.c_str());
		yuv_image_list_.push_back(image0);
	}

}
		//贴图
	{
		POINT pt = { 0, 0 };
		int nCouont = 0;
		for (auto& it : yuv_image_list_)
		{
			ImageFrame* image_frame = it.GetOriImageFrame(0);
			if (image_frame)
			{
				if (nCouont==0)
				{
					CopyI420Data(Logo_NE/*SIZENW*/, data_ret, image_frame->data_, image_frame->width_, image_frame->height_, image_frame->alpha_ ? kYuvDataTypeImageAlpha : kYuvDataTypeImage, pt);
				}
				else{
					CopyI420Data(Logo2_NE/*SIZENW*/, data_ret, image_frame->data_, image_frame->width_, image_frame->height_, image_frame->alpha_ ? kYuvDataTypeImageAlpha : kYuvDataTypeImage, pt);
				}
			}
			nCouont++;
		}
	}

猜你喜欢

转载自blog.csdn.net/shuilan0066/article/details/87881329
今日推荐