UE5 DownloadImage加载jpg失败的解决方法

DownloadImage加载jpg失败的解决方法

  • 现象
  • 解决方案
    • 具体方法

现象

用UE自带的 DownloadImage 无法下载成功,从 failure 引脚出来。
接入一个由监控器自动保存起的图像,有些可以正常加载成功,有些无法加载成功。
经调查问题出现在,有些由监控摄像头保存起来的图片的格式不符合UE的格式要求。有可能是没有MipMap的设置。
所以无法通过 【FImageUtils::ImportBufferAsTexture2D】将下载下来的图片二进制数据转换成Texture2D;
也无法通过将 【FFileHelper::SaveArrayToFile(ImageData, SavePath)】保存好的图片,通过
【UTexture2D
Texture = FImageUtils::ImportFileAsTexture2D(ImagePath);】导入生成 UTexture2D

解决方案

自己写一个download的方法,下载到图片的二进制数据,然后通过一个开源库 【stb_image.h】将图片重写入一个Texture2D
,重写的过程可以设定所需的一些格式。

具体方法

写一个DownloadImage的http请求,然后再写一个请求回调的方法,在请求成功后将二进制数据进行读取并写入 UTexture2D 对象

引入第三方库
在【Source】文件夹中创建第三方库文件夹,然后放入下载的库文件。只需要下载这一个文件就够了
下载地址
在这里插入图片描述
配置build.cs
在build.cs里增加一个引用文件的配置
在这里插入图片描述
在一个actor或者 UBlueprintAsyncActionBase 的子类里编写调用方法



DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FDownloadAsyncNodeResult, UTexture2D*, tex2D);
/**
 * 
 */
UCLASS()
class JGF_5_API UJGF_Http : public UBlueprintAsyncActionBase
{
	GENERATED_BODY()

	UPROPERTY(BlueprintAssignable)
	FDownloadAsyncNodeResult OnSuccess;

	UPROPERTY(BlueprintAssignable)
	FDownloadAsyncNodeResult OnFail;

	FTimerHandle TimerHandle;
	
	UFUNCTION(BlueprintCallable, meta = (WorldContext = "WorldContextObject"))
	static UJGF_Http* CallDownloadImage(UObject* WorldContextObject,  FString url,FString path="Data/DownloadImg/");
	
	uint16 checkCount=0;
	UTexture2D* Text2D;


	void DownloadImage(const FString& ImageURL, const FString& SavePath);
	void OnImageDownloadComplete(FHttpRequestPtr Request, FHttpResponsePtr Response, bool bWasSuccessful, FString SavePath);

};


// Fill out your copyright notice in the Description page of Project Settings.


#include "UtilityComponents/Http/JGF_Http.h"

#include "HttpModule.h"
#include "ImageUtils.h"
#include "Interfaces/IHttpResponse.h"
#include "Kismet/GameplayStatics.h"
#include "ThirdParty/stb_image/stb_image.h"

UJGF_Http* UJGF_Http::CallDownloadImage(UObject* WorldContextObject, FString url, FString path)
{
	auto node=NewObject<UJGF_Http>();
	FString FileName = FPaths::ConvertRelativePathToFull(FPaths::ProjectDir());
	FileName = FileName.Append(path);
	node ->DownloadImage(url,FileName);
	auto check=[node,WorldContextObject,url]()
	{
		if(node->Text2D!=nullptr)
		{
			node->OnSuccess.Broadcast(node->Text2D);
			WorldContextObject->GetWorld()->GetTimerManager().ClearTimer(node->TimerHandle);
		}else
		{
			node->checkCount++;
			if(node->checkCount>100)
			{
				node->OnFail.Broadcast(nullptr);
				WorldContextObject->GetWorld()->GetTimerManager().ClearTimer(node->TimerHandle);
			}
		}
	};
	WorldContextObject->GetWorld()->GetTimerManager().SetTimer(node->TimerHandle,FTimerDelegate::CreateLambda(check),0.1f,true);
	return  node;
}

void UJGF_Http::DownloadImage(const FString& ImageURL, const FString& SavePath)
{
	// 创建 HTTP 请求对象
	TSharedRef<IHttpRequest> HttpRequest = FHttpModule::Get().CreateRequest();
	HttpRequest->OnProcessRequestComplete().BindUObject(this, &UJGF_Http::OnImageDownloadComplete, SavePath);
    
	HttpRequest->SetURL(ImageURL);
	HttpRequest->SetVerb("GET");
	HttpRequest->SetHeader(TEXT("Content-Type"), TEXT("image/jpeg"));
	HttpRequest->ProcessRequest();
}

void UJGF_Http::OnImageDownloadComplete(FHttpRequestPtr Request, FHttpResponsePtr Response, bool bWasSuccessful,
	FString SavePath)
{
	if (bWasSuccessful)
	{
		// 获取图片数据
		const TArray<uint8>& ImageData = Response->GetContent();
		
		// 将数据转换为 `stb_image` 支持的格式
		int32 Width, Height, Channels;
		unsigned char* ImageData_1 = stbi_load_from_memory(ImageData.GetData(), ImageData.Num(), &Width, &Height, &Channels, 0);
		if (!ImageData_1)
		{
			return;
		}
		UTexture2D* Texture = UTexture2D::CreateTransient(Width, Height);
		if (Texture)
		{
			// 锁定 BulkData 以便修改
			FTexture2DMipMap& Mip = Texture->PlatformData->Mips[0];
			void* TextureData = Mip.BulkData.Lock(LOCK_READ_WRITE);

			// 根据图片通道数处理图像数据
			FColor* Pixels = new FColor[Width * Height];
			int32 PixelIndex = 0;

			for (int32 y = 0; y < Height; ++y)
			{
				for (int32 x = 0; x < Width; ++x)
				{
					int32 Index = (y * Width + x) * Channels;

					// 确保按照正确的通道顺序进行复制
					if (Channels == 4)  // RGBA
					{
						Pixels[PixelIndex++] = FColor(ImageData_1[Index + 0], ImageData_1[Index + 1], ImageData_1[Index + 2], ImageData_1[Index + 3]);
					}
					else if (Channels == 3)  // RGB, 默认 alpha = 255
					{
						Pixels[PixelIndex++] = FColor(ImageData_1[Index + 0], ImageData_1[Index + 1], ImageData_1[Index + 2], 255);
					}
				}
			}

			// 将像素数据复制到纹理中
			FMemory::Memcpy(TextureData, Pixels, Width * Height * sizeof(FColor));

			// 解锁 BulkData
			Mip.BulkData.Unlock();

			// 释放临时图像数据和像素数据
			stbi_image_free(ImageData_1);
			delete[] Pixels;

			// 更新纹理资源
			Texture->UpdateResource();
		}

		if(Texture)
			Text2D=Texture;


		
		//Text2D= FImageUtils::ImportBufferAsTexture2D(ImageData);
		// 保存到本地文件
		//FFileHelper::SaveArrayToFile(ImageData, *SavePath);
        
		// 调用处理和加载图片的函数
		//ProcessAndLoadImage(SavePath);
	}
	else
	{
		UE_LOG(LogTemp, Warning, TEXT("Image download failed"));
	}
}

代码说明
在这里插入图片描述

注 【SavePath】参数暂时无用,并没有保存到本地
在actor中调用【CallDownloadImage】进行下载
在进而调用了【DownloadImage】进行http下载文件
完成后回调到【OnImageDownloadComplete】,进行数据处理
处理过程中,直接将二进制图片数据通过stb_image库重新转化一遍成 char* ,写入 FColor 再在写入 UTexture2D 对象RGB

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/920348.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Springboot 整合 Java DL4J 搭建智能问答系统

&#x1f9d1; 博主简介&#xff1a;CSDN博客专家&#xff0c;历代文学网&#xff08;PC端可以访问&#xff1a;https://literature.sinhy.com/#/literature?__c1000&#xff0c;移动端可微信小程序搜索“历代文学”&#xff09;总架构师&#xff0c;15年工作经验&#xff0c;…

相较于发达国家约70%的普及率,中国【台式洗碗机】渗透率仅在2%-3%之间,潜在市场增量可观

内容摘要 据 HengCe 最新调研&#xff0c;2023年中国台式洗碗机市场销售收入达到了 万元&#xff0c;预计2030年可以达到 万元&#xff0c;2024-2030期间年复合增长率(CAGR)为 %。本研究项目旨在梳理台式洗碗机领域产品系列&#xff0c;洞悉行业特点、市场存量空间及增量空间&…

自动语音识别(ASR)与文本转语音(TTS)技术的应用与发展

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…

基于python的机器学习(四)—— 聚类(一)

目录 一、聚类的原理与实现 1.1 聚类的概念和类型 1.2 如何度量距离 1.2.1 数据的类型 1.2.2 连续型数据的距离度量方法 1.2.3 离散型数据的距离度量方法 1.3 聚类的基本步骤 二、层次聚类算法 2.1 算法原理和实例 2.2 算法的Sklearn实现 2.2.1 层次聚类法的可视化实…

算法知识-12-指针

概念 指针是一个变量&#xff0c;它存储的是另一个变量的内存地址。 基础使用指针 //声明 int* ptr; // 声明一个指向 int 类型的指针 //初始化 int num 5; int* ptr2 &num; // 使 ptr2 指向 num 的地址 //访问值 cout << *ptr2; // 输出 ptr2 所指向的 num …

图像上显示中文文本 - python 实现

该示例是在图像上显示中文文本&#xff0c;并用opencv的显示方式显示。 注意&#xff1a;SimHei.ttf&#xff08;黑体字体&#xff09;为字体文件&#xff0c;Windows 默认字体路径&#xff1a;C:/Windows/Fonts/SimHei.ttf 具体实现代码如下&#xff1a; # -*-coding:utf-8…

uniapp rpx兼容平板

问题: 使用uniapp开发平板端时, rpx/upx 内容过小, 没有适应屏幕 原因: uniapp 默认支持最大设备宽度为960px 而平板宽度超出了960 uniapp官方文档https://uniapp.dcloud.io/collocation/pages?idglobalstyle 解决: // pages.json 文件&#xff1a; {//..."globalSt…

【隐私计算大模型】联邦深度学习之拆分学习Split learning原理及安全风险、应对措施以及在大模型联合训练中的应用案例

Tips&#xff1a;在两方场景下&#xff0c;设计的安全算法&#xff0c;如果存在信息不对等性&#xff0c;那么信息获得更多的一方可以有概率对另一方实施安全性攻击。 1. 拆分学习原理 本文介绍了一种适用于隐私计算场景的深度学习实现方案——拆分学习&#xff0c;又称分割…

Java函数式编程基础之【Optional类】详解

一、概述 Optional 是 Java 8 引入的新特性&#xff0c;它是一种特殊的包装类&#xff0c;里面只存储一个元素&#xff08;这一点与基本数据类型的包装类有点相似&#xff09;。有的文档称其为容器类&#xff0c;但它不同于 Conllection框架中的集合类&#xff0c;它一个容器只…

stm32与ht7038的项目

最近做了一个stm32与ht7038的数据采集项目 硬件包含太阳能充电电路 ht7038采集芯片电路 buck电路 stm32最小系统电路和lora模块电路 硬件PCB如下图所示 ht7038的程序如下所示ht7038.c #include "ht7038.h" #include "stm32l0xx_hal_spi.h"typedef uint8…

AbsPlus框架介绍2

ABSPlus框架以其集成的多功能性在市场上脱颖而出。它不仅提供美观且符合主流风格的页面设计&#xff0c;还支持灵活的流程配置&#xff0c;包括算法处理流程和页面审批流程。在众多业务系统中&#xff0c;流程管理往往是核心且复杂的挑战&#xff0c;涉及数据库设计、页面开发以…

springboot基于微信小程序的食堂预约点餐系统

摘 要 基于微信小程序的食堂预约点餐系统是一种服务于学校和企事业单位食堂的智能化解决方案&#xff0c;旨在提高食堂就餐的效率、缓解排队压力&#xff0c;并优化用户的就餐体验。系统作为一种现代化的解决方案&#xff0c;为食堂管理和用户就餐提供了便捷高效的途径。它不仅…

免费的视频混剪综合处理工具介绍与下载

免费的视频混剪综合处理工具 软件截图 功能 支持&#xff1a; 这个软件主要用于视频的批量处理&#xff0c;包括添加水印、裁剪、画中画、去水印、去头尾、变速、文本和背景音乐等功能。以下是界面中一些主要功能的介绍&#xff1a; 视频队列&#xff1a;显示当前待处理的视…

2024年亚太数学建模竞赛问题C宠物产业及相关产业发展分析与对策

随着人们消费理念的发展&#xff0c;随着经济的快速发展和人均收入的提高&#xff0c;宠物产业作为一个新兴产业在全球范围内逐渐积聚势头。1992年&#xff0c;中国小动物保护协会成立&#xff0c;随后1993年&#xff0c;皇家狗狗、玛氏等国际宠物品牌进入中国市场。随着“宠物…

如何默认VS2019用管理员方式打开

1.通过快捷方式找到“Visual Studio 2019”所在文件夹。 2.继续在"Visual Studio 2019"右键菜单&#xff0c;打开“devenv.exe”所在文件夹。 3.在“devenv.exe”右键菜单&#xff0c;选择“兼容性疑难解答”。 4.选择“疑难解答程序”。 5.选择勾选“该程序需要附加…

鸿蒙UI开发与部分布局

UI开发 1. 布局概述 1.1 开发流程 1.先确定开发流程 -> 2.分析页面元素构成 ->3.选用合适的布局容器组件 1.3 布局元素组成&#xff1a;盒模型 2.1 布局分类 2.1 线性布局 线性布局是开发中最常用、最基础的布局&#xff0c;通过线性容器Row和Column构建 2.1.1 线性布…

Python中Tushare(金融数据库)入门详解

文章目录 Python中Tushare&#xff08;金融数据库&#xff09;入门详解一、引言二、安装与注册1、安装Tushare2、注册与获取Token 三、Tushare基本使用1、设置Token2、获取数据2.1、获取股票基础信息2.2、获取交易日历2.3、获取A股日线行情2.4、获取沪股通和深股通成份股2.5、获…

性能优化(二):ANR

介绍 ANR全称Application Not Responding&#xff0c;意思就是程序未响应。如果一个应用无法响应用户的输入&#xff0c;系统就会弹出一个ANR对话框&#xff0c;用户可以自行选择继续等待亦或者是停止当前程序。 Android系统会监控程序的响应状况&#xff0c;一旦出现下面情况…

神经网络问题之:梯度不稳定

梯度不稳定是深度学习中&#xff0c;特别是在训练深度神经网络时常见的一个问题&#xff0c;其本质涉及多个方面。 一、根本原因 梯度不稳定问题的根本原因在于深度神经网络的结构和训练过程中的一些固有特性。随着网络层数的增加&#xff0c;梯度在反向传播过程中会逐层累积变…

弹幕发送功能‘简单’实现

导入依赖 <!-- websocket弹幕依赖 --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-websocket</artifactId></dependency>后端代码 package com.by.danmaku;import org.springfra…