Duilib多标签选项卡拖拽效果:添加动画特效!

news2024/11/24 20:43:03

动画是小型界面库的“难题”、“通病”

请添加图片描述

几年前就有人分享了如何用direct UI制作多标签选项卡界面的方法。还有人出了一个简易的浏览器demo。但是他们的标签栏都没有Chrome浏览器那样的动画特效。

如何给界面添加布局是的动画特效呢?

动画使界面看起来高大上,使用起来也更直观。

我调查了一些小型界面库,包括imgui、lcui等,都没有内置这样的组件。

难道仅仅为了这一个小的控件效果,真的要内置一个浏览器?(sortablejs?)


多标签选项卡拖拽效果 【三百行精简版本】

Duilib多标签选项卡拖拽效果 - 知乎
洋洋洒洒八百行 —— 大多是图标啊,背景啊之类的。然后他还特别设计了。子控件类型和父控件配套使用。太麻烦了。

我简化一番,将原理呈现,只需三百行:


class CTabBarUI :public CHorizontalLayoutUI
{
public:
    CTabBarUI();
    ~CTabBarUI();

    LPCTSTR GetClass() const;
    LPVOID GetInterface(LPCTSTR pstrName);

    //添加一个
    CControlUI* AddItem(LPCTSTR pstrText);

    //drag
    void DoDragBegin(CControlUI *pTab);
    void DoDragMove(CControlUI *pTab, const RECT& rcPaint);
    void DoDragEnd(CControlUI *pTab, const POINT& Pt);

private:
	CControlUI *m_pZhanWeiOption = NULL;
    CControlUI *m_pDragOption = NULL;

};


#define DUI_MSGTYPE_OPTIONTABCLOSE 		   	(_T("closeitem_tabbar"))


//


std::function<bool(CControlUI* this_, HDC hDC, const RECT& rcPaint)> postDraw;
std::function<bool(CControlUI* this_, TEventUI& evt)> evtListener;

POINT m_ptLastMouse;
POINT m_ptLButtonDownMouse;
RECT m_rcNewPos;

//判断开始拖拽
bool m_bFirstDrag = true;

//判断是否忽略拖拽,首次需要鼠标按住拖拽一定距离才触发拖拽
bool m_bIgnoreDrag = true;

//
//
CTabBarUI::CTabBarUI()
{
	m_pZhanWeiOption = new CControlUI();
	m_pZhanWeiOption->SetMaxWidth(0);
	m_pZhanWeiOption->SetForeColor(0x000000ff);
	m_pZhanWeiOption->SetEnabled(false);

	Add(m_pZhanWeiOption);
	auto box = this;
	postDraw = [box](CControlUI* this_, HDC hDC, const RECT& rcPaint)
	{
		return true;
	};

	evtListener = [box](CControlUI* this_, TEventUI& event)
	{
		//if (!this_->IsMouseEnabled() && event.Type > UIEVENT__MOUSEBEGIN && event.Type < UIEVENT__MOUSEEND) {
		//	if (box != NULL) box->DoEvent(event);
		//	else COptionUI::DoEvent(event);
		//	return true;
		//}

		auto _manager = box->GetManager();
		auto & m_rcItem = this_->GetPos();
		if (event.Type == UIEVENT_BUTTONDOWN)
		{
			if (::PtInRect(&this_->GetPos(), event.ptMouse) && this_->IsEnabled())
			{
				this_->m_uButtonState |= UISTATE_PUSHED | UISTATE_CAPTURED;
				this_->Invalidate();
				if (this_->IsRichEvent()) _manager->SendNotify(this_, DUI_MSGTYPE_BUTTONDOWN);

				if (::PtInRect(&this_->GetPos(), event.ptMouse)/* && !::PtInRect(&rcClose, event.ptMouse)*/)
				{
					this_->Activate();
				}

				m_bIgnoreDrag = true;
				m_ptLButtonDownMouse = event.ptMouse;
				m_ptLastMouse = event.ptMouse;
				m_rcNewPos = m_rcItem;
				if (_manager)
				{
					_manager->RemovePostPaint(this_);
					_manager->AddPostPaint(this_);
				}

			}
		}
		else if (event.Type == UIEVENT_MOUSEMOVE)
		{
			if ((this_->m_uButtonState & UISTATE_CAPTURED) != 0)
			{
				LONG cx = event.ptMouse.x - m_ptLastMouse.x;
				LONG cy = event.ptMouse.y - m_ptLastMouse.y;

				m_ptLastMouse = event.ptMouse;

				RECT rcCurPos = m_rcNewPos;

				rcCurPos.left += cx;
				rcCurPos.right += cx;
				rcCurPos.top += cy;
				rcCurPos.bottom += cy;

				//将当前拖拽块的位置 和 当前拖拽块的前一时刻的位置,刷新
				CDuiRect rcInvalidate = m_rcNewPos;
				m_rcNewPos = rcCurPos;
				rcInvalidate.Join(m_rcNewPos);
				if (_manager) _manager->Invalidate(rcInvalidate);

				this_->NeedParentUpdate();
			}
		}
		else if (event.Type == UIEVENT_BUTTONUP)
		{
			if ((this_->m_uButtonState & UISTATE_CAPTURED) != 0)
			{
				this_->m_uButtonState &= ~(UISTATE_PUSHED | UISTATE_CAPTURED);
				this_->Invalidate();

				CTabBarUI* pParent = static_cast<CTabBarUI*>(box);
				if (pParent)
				{
					pParent->DoDragEnd(this_, m_ptLastMouse);
				}

				if (_manager)
				{
					_manager->RemovePostPaint(this_);
					_manager->Invalidate(m_rcNewPos);
				}
				this_->NeedParentUpdate();

				m_bFirstDrag = true;
			}
		}


		if ((this_->m_uButtonState & UISTATE_CAPTURED) != 0)
		{
			auto & m_rcItem = this_->GetPos();
			lxxx(m_bIgnoreDrag dd, 13)
				if (m_bIgnoreDrag && abs(m_ptLastMouse.x - m_ptLButtonDownMouse.x) < 15)
				{
					return true;
				}
			m_bIgnoreDrag = false;
			lxxx(dd, 13)

				CTabBarUI* pParent = static_cast<CTabBarUI*>(box);
			//if (!pParent) return true;

			if (m_bFirstDrag)
			{
				pParent->DoDragBegin(this_);
				m_bFirstDrag = false;
				return true;
			}

			CDuiRect rcParent = box->GetPos();
			RECT rcUpdate = { 0 };
			rcUpdate.left = m_rcNewPos.left < rcParent.left ? rcParent.left : m_rcNewPos.left;
			rcUpdate.top = m_rcItem.top < rcParent.top ? rcParent.top : m_rcItem.top;
			rcUpdate.right = m_rcNewPos.right > rcParent.right ? rcParent.right : m_rcNewPos.right;
			rcUpdate.bottom = m_rcItem.bottom > rcParent.bottom ? rcParent.bottom : m_rcItem.bottom;
			//CRenderEngine::DrawColor(hDC, rcUpdate, 0xAAFFFFFF);

			pParent->DoDragMove(this_, rcUpdate);

		}
		return true;
	};


}


CTabBarUI::~CTabBarUI()
{
}

LPCTSTR CTabBarUI::GetClass() const
{
	return _T("TabBarUI");
}

LPVOID CTabBarUI::GetInterface(LPCTSTR pstrName)
{
	if (_tcsicmp(pstrName, _T("TabBar")) == 0) return static_cast<CTabBarUI*>(this);
	return CHorizontalLayoutUI::GetInterface(pstrName);
}

CControlUI* CTabBarUI::AddItem(LPCTSTR pstrText)
{
	if (!pstrText)
	{
		return NULL;
	}

	CLabelUI* pTab = new CLabelUI();
	pTab->evtListeners.push_back(evtListener);
	pTab->postDraws.push_back(postDraw);
	pTab->SetRichEvent(true);

	//pTab->SetName(_T("tabbaritem"));
	//pTab->SetGroup(_T("tabbaritem"));
	pTab->SetTextColor(0xff333333);
	//pTab->SetNormalImage(_T("file='img/bk_tabbar_item.png' source='0,0,10,8' corner='4,4,4,2'"));
	//pTab->SetHotImage(_T("file='img/bk_tabbar_item.png' source='10,0,20,8' corner='4,4,4,2'"));
	//pTab->SetSelectedImage(_T("file='img/bk_tabbar_item.png' source='20,0,30,8' corner='4,4,4,2'"));
	pTab->SetMaxWidth(226);
	//pTab->SetFixedWidth(100);
	pTab->SetMinWidth(20);
	//pTab->SetBorderRound({ 2, 2 });
	pTab->SetText(pstrText);

	pTab->SetAttribute(_T("align"), _T("left"));
	pTab->SetAttribute(_T("textpadding"), _T("28,0,16,0"));
	pTab->SetAttribute(_T("iconsize"), _T("16,16"));
	pTab->SetAttribute(_T("iconpadding"), _T("6,0,0,0"));
	pTab->SetAttribute(_T("iconimage"), _T("img/icon_360.png"));
	pTab->SetAttribute(_T("selectediconimage"), _T("img/icon_baidu.png"));
	pTab->SetAttribute(_T("endellipsis"), _T("true"));

	pTab->SetAttribute(_T("haveclose"), _T("true"));
	pTab->SetAttribute(_T("closepadding"), _T("0,0,6,0"));
	pTab->SetAttribute(_T("closesize"), _T("16,16"));
	pTab->SetAttribute(_T("closeimage"), _T("file='img/btn_tabbaritem.png' source='0,0,16,16'"));
	pTab->SetAttribute(_T("closehotimage"), _T("file='img/btn_tabbaritem.png' source='16,0,32,16'"));
	pTab->SetAttribute(_T("closepushimage"), _T("file='img/btn_tabbaritem.png' source='32,0,48,16'"));

	//pTab->OnNotify += MakeDelegate(this, &CTabBarUI::OnItemClose);

	if (Add(pTab))
	{
		return pTab;
	}
	return NULL;
}

void CTabBarUI::DoDragBegin(CControlUI *pTab)
{
	if (!pTab)
	{
		return;
	}

	int index = GetItemIndex(pTab);
	if (index < 0)
	{
		return;
	}

	int index_blue = GetItemIndex(m_pZhanWeiOption);
	if (index_blue < 0)
	{
		return;
	}

	m_pDragOption = pTab;

	m_items.SetAt(index, m_pZhanWeiOption);
	m_items.SetAt(index_blue, m_pDragOption);

	m_pZhanWeiOption->SetMaxWidth(m_pDragOption->GetWidth());
	m_pDragOption->SetMaxWidth(0);
}

void CTabBarUI::DoDragMove(CControlUI *pTab, const RECT& rcPaint)
{
	if (m_pDragOption != pTab)
	{
		return;
	}

	int x = rcPaint.left + (rcPaint.right - rcPaint.left) / 2;
	int y = rcPaint.top + (rcPaint.bottom - rcPaint.top) / 2;
	if (x < m_rcItem.left || x > m_rcItem.right)
	{
		return;
	}

	int index = -1;
	for (int it1 = 0; it1 < m_items.GetSize(); it1++) 
	{
		CControlUI* pControl = static_cast<CControlUI*>(m_items[it1]);
		if (!pControl) continue;
		if(pControl!=m_pZhanWeiOption)
		if (/*_tcsicmp(pControl->GetClass(), _T("tabbaritemui")) == 0 && */::PtInRect(&pControl->GetPos(), { x, y }))
		{
			index = it1;
			break;
		}
	}

	if (index == -1)
	{
		return;
	}

	CControlUI *pOption = static_cast<CControlUI*>(GetItemAt(index));
	int index_blue = GetItemIndex(m_pZhanWeiOption);

	m_items.SetAt(index, m_pZhanWeiOption);
	m_items.SetAt(index_blue, pOption);

}

void CTabBarUI::DoDragEnd(CControlUI *pTab, const POINT& Pt)
{
	if (m_pDragOption != pTab)
	{
		return;
	}

	int index = GetItemIndex(m_pDragOption);
	if (index < 0)
	{
		return;
	}

	int index_blue = GetItemIndex(m_pZhanWeiOption);
	if (index_blue < 0)
	{
		return;
	}

	m_items.SetAt(index, m_pZhanWeiOption);
	m_items.SetAt(index_blue, m_pDragOption);

	m_pDragOption->SetMaxWidth(m_pZhanWeiOption->GetWidth());
	m_pZhanWeiOption->SetMaxWidth(0);
}

和chrome浏览器不同的是他没有使用标准的拖拽事件,而是分别处理了点击触摸移动事件。


DirectUI 动画方案入门

Direct是比较早的,他的技术比较老。他是直接用那个hdc绘制。和普通的win程序是一样的。区别仅仅是使用自己的布局系统。然后他的控件大多是没有句柄的。所以说比较直接。

最初的DirectUI 公开方案里的动画。那个是dx插特效,是不一样的,在播放dx特效之时,会有一个阻塞之类的,特效组合也不是很自由。

其实很简单,无非是三种方法:

  1. 最简单的timer
  2. 循环Invalidate
  3. 用一个新的线程去控制它刷新。

第三和第二很相似。第二个循环Invalidate是一个折中。

为了入门,简单实现上面动图中的滚动跑马灯特效:

float xx;
int tick;

			auto updateFun = [newbar, menu](float spd){
				int t = GetTickCount64(), dt = t-tick[i];
				xx += dt * spd;
				tick = t;
				menu->SetFixedXY({(int)round(xx),0});
				if (xx>newbar->GetWidth()-menu->GetWidth())
				{
					xx = 0;
				}
				return dt;
			};

			if (开始滚动)
			{
				newbar->postDraws.push_back([updateFun, newbar](CControlUI* thiz, HDC hDC, const RECT& rcPaint){
					int dt = updateFun(.45f);
					newbar->NeedUpdate(); 
					Sleep(1);
					return true;
				});
			}

这个需要修改界面库代码在绘制之后调用传进去的函数:

DuiLib\Core\UIControl.cpp

bool CControlUI::DoPaint(HDC hDC, const RECT& rcPaint, CControlUI* pStopControl)
	{
	...
	
		if (postDraws.size())
		{
			for (size_t i = 0; i < postDraws.size(); i++)
			{
				auto ret = postDraws[i](this, hDC, rcPaint);
				if (!ret)
				{
					postDraws.erase(postDraws.begin()+i);
				}
			}
		}
		return true;
	}

类似于安卓的循环postInvalidate。

注意需要睡眠一秒钟。不然跑的太快,CPU飙升过于明显。当然最大值也不是很大,就是sleep调度一下的话,性能变得很轻盈。


WinQkUI 标签动画

有了这个基础之后,我们就可以实现界面拖拽排序之时的动画效果。

也是需要修改这个源代码库。循环Invalidate还是在dopaint方法内部末尾调用,但是设置位置偏移的话,须在setpos之后调用。


void CTabBarUI::DoDragMove(CControlUI *pTab, const RECT& rcPaint)
{
	...

	AnimationJob* job = new AnimationJob{true, pItem->GetPos().left, pItem->GetPos().top
			, GetTickCount64(), 200};

	auto animator = [job](CControlUI* this_, RECT& rcItem)
	{
		int ww = rcItem.right - rcItem.left;
		int hh = rcItem.bottom - rcItem.top;
		int time = GetTickCount64() - job->start;
		if (time>job->duration)
			time = job->duration;
		if (time>=job->duration)
			job->active = false;
		rcItem.left = job->xx + (rcItem.left - job->xx)*1.f/job->duration*time;
		rcItem.top = job->yy + (rcItem.top - job->yy)*1.f/job->duration*time;
		rcItem.right = rcItem.left + ww;
		rcItem.bottom = rcItem.top + hh;
		//this_->NeedParentUpdate();
		//this_->GetParent()->NeedUpdate();
		//Sleep(1);
		return job->active;
	};

	pItem->postSize.resize(0);
	pItem->postSize.push_back(animator);	
	//if (1)
	//{
	//	return;
	//}
	pItem->_view_states |= VIEWSTATEMASK_IsAnimating;
	pItem->postDraws.push_back([job](CControlUI* thiz, HDC hDC, const RECT& rcPaint)
	{
		if (job->active)
		{
			//RECT* rcItem = (RECT*)&thiz->GetPos();
			int time = GetTickCount64() - job->start;
			if (time>job->duration)
				time = job->duration;
			//if (time>=job->duration)
			//	job->active = false;
			thiz->GetParent()->NeedUpdate();
			//Sleep(1);
		} else {
			thiz->postSize.resize(0);
			thiz->_view_states &= ~VIEWSTATEMASK_IsAnimating;
			delete job;

		}
		return job->active;
	});

}

后面的代码不是很完整,但原理已经讲得十分清楚了。待我整理一番再上传。

只需在DoDragMove方法。在触发交换元素位置的时候,为每个被移动的元素安排动画 AnimationJob 就行。

struct AnimationJob{
	bool active;
	LONG xx;
	LONG yy;
	ULONGLONG start;
	int duration;
};

AnimationJob 结构体记录起始位置,然后根据一个动画时长,一路插值到目标位置即可。

目标位置由父容器布局,由 setPos 决定。

在postSize的循环中,实时修改动画过程中控件的位置,不直接采用setPos 的值,从而实现布局动画,原理十分的简单。

在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

AbstractMap和SimpleEntry

一、AbstractMap 位置&#xff1a;在java.util包 二、SimpleEntry 1、概述 继承了Map中的内部接口Entry<K,V> SimpleEntry<K,V>不仅继承了Map.Entry<K,V>&#xff0c;还继承了序列化的接口 2、构造方法 方法说明SimpleEntry(K key,V value)通过键值对初…

美团大规模KV存储挑战与架构实践--图文分析

美团大规模KV存储挑战与架构实践–图文分析 原作者&#xff1a;美团技术团队 原文链接&#xff1a;https://tech.meituan.com/2024/03/15/kv-squirrel-cellar.html 1 美团 KV 存储发展历程 第一代&#xff1a;使用Memcached 什么是一致性哈希&#xff1f; 哈希&#xff1a…

[Mdfs] lc3067. 在带权树网络中统计可连接服务器对数目(邻接表+图操作基础+技巧+好题)

文章目录 1. 题目来源2. 题目解析 1. 题目来源 链接&#xff1a;3067. 在带权树网络中统计可连接服务器对数目 2. 题目解析 挺有意思的一道题目&#xff0c;重点是要能够读懂题目&#xff0c;然后结合几个图相关的处理技巧即可拿下。 图存储&#xff1a;邻接表即可。无向无…

【Redis】什么是Redis缓存 雪崩、穿透、击穿?(一篇文章就够了)

目录 什么是Redis? Redis的正常存储流程&#xff1f; 什么是Redis缓存雪崩&#xff1f; 缓存雪崩 缓存预热 缓存失效时间的随机性 什么是Redis缓存穿透&#xff1f; 缓存穿透 缓存空对象 BloomFilter&#xff08;布隆过滤器&#xff09; 什么是Redis缓存击穿&#…

LabVIEW 用于 MES 系统和卡钳上位机检测

LabVIEW 确实可以用于制造执行系统&#xff08;MES&#xff09;的开发以及卡钳上位机检测。以下是详细说明&#xff1a; 使用 LabVIEW 开发 MES 系统 数据采集与处理&#xff1a;LabVIEW 擅长实时数据采集和处理&#xff0c;可以连接多种传感器和设备&#xff0c;获取生产线上…

Spark作业运行异常慢的问题定位和分析思路

一直很慢 &#x1f422; 运行中状态、卡住了&#xff0c;可以从以下两种方式入手&#xff1a; 如果 Spark UI 上&#xff0c;有正在运行的 Job/Stage/Task&#xff0c;看 Executor 相关信息就好。&#x1f4bb; 第一步&#xff0c;如果发现卡住了&#xff0c;直接找到对应的…

YoloV9改进策略:主干网络篇|MobileNetV4主干替换YoloV9的BackBone(独家原创)

摘要 今年&#xff0c;轻量级王者MobileNetV4闪亮登场&#xff01;在我们这篇文章里&#xff0c;我们把MobileNetV4加入到了YoloV9中&#xff0c;对MobileNetV4的层数和卷积层核做了适当的修改&#xff0c;然后替换原有的BackBone。哈哈&#xff0c;你猜怎么着&#xff1f;效果…

整除及求余运算符、数字的提取、顺序结构程序

1.运算符 在有余数的除法运算中&#xff0c;如果要知道商和余数分别是多少&#xff0c;可以用/和%这两个运算符号来得到。 (1)/(整除)&#xff0c;当被除数和除数均为整数时&#xff0c;结果也为整型&#xff0c;只取商的整数部分。 如:10/25 10/33 5/10 0 (2)%(求余)&…

2024年最详细的Studio One 6.6.1中文破解版图文安装激活指南(附Keygen下载)

Studio One 6是一款非常专业的音乐创作编辑软件。为用户提供了所有一切你所需要创作的功能&#xff0c;包括所有的歌曲、项目、仪表板等动能&#xff0c;而且还自定义添加配置文件&#xff0c;良好的界面交互和丰富的功能板块&#xff0c;再结合优秀的性能&#xff0c;能够满足…

苹果跌穿4500元,反噬国产手机,这算是自作自受吧!

618大促还在进行中&#xff0c;苹果仍然在降价&#xff0c;iPhone15已是618大促最畅销的手机&#xff0c;国产手机没有谁能超越它了&#xff0c;或许是国产手机眼见着已无法击败苹果&#xff0c;选择涨价&#xff0c;能卖一部算一部&#xff0c;多赚一点钱了吧。 苹果的iPhone1…

工业互联网数字中台建设方案(ppt原件)

工业互联网数字中台解决方案旨在为企业提供全面、高效的数据驱动能力。该方案主要包括以下几个核心部分&#xff1a; 数据中台&#xff1a;作为核心&#xff0c;数据中台负责汇聚、整合、提纯和加工各类工业数据&#xff0c;实现数据资产的标准化、模型化和模块化。通过提供API…

【Oracle】Oracle导入导出dmp文件

文章目录 前言一、什么是dmp&#xff1f;二、imp/impdp、exp/expdp对比及示例1.区别2.imp/impdp对比及示例a. impb. impbp 3.exp/expdp对比及示例a. expb.expdp 3.其他事项 三、执行导入导出前置条件1.创建角色并授权2.创建目录映射 前言 在工作中&#xff0c;经常会遇到需要备…

基于关键词自动采集抖音视频排名及互动数据(点赞、评论、收藏)

在当今的社交媒体时代&#xff0c;抖音作为一个热门短视频平台&#xff0c;吸引了大量用户和内容创作者。对于研究和分析抖音上的热门视频及其互动数据&#xff08;如点赞、评论、收藏等&#xff09;&#xff0c;自动化的数据采集工具显得尤为重要。本项目旨在开发一个基于关键…

Linux基础I/O

一&#xff0c;系统文件I/O 写文件: #include <stdio.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <unistd.h> #include <string.h> int main() {umask(0);int fd open("myfile", O_WRO…

【Java】解决Java报错:StackOverflowError

文章目录 引言1. 错误详解2. 常见的出错场景2.1 无限递归2.2 递归深度过大2.3 方法调用层次过深 3. 解决方案3.1 优化递归算法3.2 尾递归优化3.3 增加调用栈大小3.4 检查递归终止条件 4. 预防措施4.1 使用迭代替代递归4.2 尾递归优化4.3 合理设计递归算法4.4 调整JVM参数4.5 定…

【Qt】Qt QTreeWidget隐藏列名称(横向表头)

1. 效果 未隐藏 隐藏 2. 方法 方法1 ui->treeWidget->header()->hide();方法2 ui->treeWidget->header()->setVisible(false);

RDK X3(aarch64) 测试手柄

0. 环境 - 亚博智能的ROSMASTER-X3 标准版 - XDK X3 1.0 - 冰原狼等win10免驱的手柄 1. RDK X3 1.0 串口通信 波特率 921600 root/root mobaterm -> Session -> VNC -> 192.168.8.108:5900 -> runrise 2. 测试 ROSMASTER-X3 标准版 配套的手柄 安装 …

【Java SE】字符串常量池详解,什么情况下字符串String对象存在常量池,通过==进行判断,字符串创建及截取后是否同一个对象

复习字符串创建方式 字符串的31种构造方法 public String();创建一个空白字符串&#xff0c; 不含有任何内容public String(char[] array);根据字符数组的内容&#xff0c;来创建对应的字符串public String(byte[] array);根据字节数组的内筒&#xff0c;来创建对应的字符串 …

物联网设计竞赛_8_Jetson Orin Nano安装pytorch与torchvision

我的新板子到了&#xff0c;型号是jetson orin Nano与之前的jetson nano稍有不同我发现库又得从新下载 我的pip3的版本是3.8.10&#xff0c;jetpack版本5.1.1&#xff0c;又得重新开始下载库&#x1f62d; 安装pytorch: 得科学上网&#xff1a; PyTorch for Jetson - Jetson …

U-Net: Convolutional Networks for Biomedical Image Segmentation--论文笔记

U-Net: Convolutional Networks for Biomedical Image Segmentation 资料 1.代码地址 2.论文地址 https://arxiv.org/pdf/1505.04597 3.数据集地址 论文摘要的翻译 人们普遍认为&#xff0c;深度网络的成功训练需要数千个带注释的训练样本。在本文中&#xff0c;我们提出…