文章目录

  • 1 在回调函数中实现
  • 2 独立封装调用
    • 2.1 获取图像宽、高、pBuffer、channel
    • 2.2 内存图像数据截取ROI并显示
    • 2.3 回调函数调用
  • 3 for循环嵌套 方法2
  • 4 for循环嵌套 方法3
  • 5 按行复制数据提高效率,但很耗内存
  • 6 unsafe代码 解释及注意事项 看我另一篇文章
  • 7 ConvertToRGB24详细解释 、示例、注意事项 看我另一篇文章
  • 8 问题与反思
    • 8.1 被反复创建和使用,需手动释放吗?
    • 8.2 创建一个全局Bitmap bitma,多线程访问会冲突吗?

当我们只要显示ROI区域的画面(显示局部细节),而不是相机整个画面时,就需要对图像数据进行截取。

对于工业相机原图像数据IFrameData 裁剪ROI,并不像 OpenCV中截取ROI那么简单, 下面提供3种方法实现(效率不同),并将ROI画面实时显示在pictureBox中,

1 在回调函数中实现

public IntPtr pBuffer = IntPtr.Zero;private void __OnFrameCallbackFun(object objUserParam, IFrameData objIFrameData)
{int channel = 0;try{if (null != objIFrameData){//************************************************************//获取图像信息,为图像处理等功能做准备//*************************************************************int imgHeight = (int)objIFrameData.GetHeight();int imgWidth = (int)objIFrameData.GetWidth();//************************************************************// 对图像进行裁剪并显示在 PictureBox 中//*************************************************************Rectangle ROI = new Rectangle(1323, 212, 2200, 1500);//获取图像bufferGX_VALID_BIT_LIST emValidBits = GX_VALID_BIT_LIST.GX_BIT_0_7;emValidBits = __GetBestValudBit(objIFrameData.GetPixelFormat());// 判断图像是否成功接收if (GX_FRAME_STATUS_LIST.GX_FRAME_STATUS_SUCCESS == objIFrameData.GetStatus()){// 在关键部分的代码前加锁lock (this){if (m_bIsColor){// 彩色图像pBuffer = objIFrameData.ConvertToRGB24(emValidBits, GX_BAYER_CONVERT_TYPE_LIST.GX_RAW2RGB_NEIGHBOUR, false);//最后一个参数是否垂直翻转图像channel = 3;}else{// 黑白图像if (__IsPixelFormat8(objIFrameData.GetPixelFormat())){pBuffer = objIFrameData.GetBuffer();}else{pBuffer = objIFrameData.ConvertToRaw8(emValidBits);}channel = 1;}PixelFormat format = new PixelFormat();format = channel == 3 ? PixelFormat.Format24bppRgb : PixelFormat.Format8bppIndexed;//若3通道彩色图像,否则黑白图像//创建ROI 空图像Bitmap bitmap = new Bitmap(ROI.Width, ROI.Height, format);BitmapData bmpData = bitmap.LockBits(new Rectangle(0, 0, ROI.Width, ROI.Height), ImageLockMode.WriteOnly, bitmap.PixelFormat);int srcStride = imgWidth * channel;// 原图每行数据长度int destStride = bmpData.Stride;// 新图每行数据长度int srcStartX = (ROI.X - 1) * channel; // ROI 起始 X 坐标在原图数据中的位置(二维视角)int srcStartY = ROI.Y - 1; // ROI 起始 Y 坐标在原图数据中的位置(二维视角)int srcOffset = srcStartY * srcStride + srcStartX; // ROI 起始位置在原图数据中的偏移量(原图数据在内存中是一行,一维数组)unsafe{byte* srcPtr = (byte*)pBuffer + srcOffset;byte* destPtr = (byte*)bmpData.Scan0;for (int y = 0; y < ROI.Height; y++){for (int x = 0; x < ROI.Width * channel; x++){destPtr[x] = srcPtr[x];}srcPtr += srcStride;destPtr += destStride;}}bitmap.UnlockBits(bmpData);// 在这里处理 bitmap 图像,下面是显示举例m_bitmap = bitmap;//将其赋值给全局的m_bitmap,从而可以在外部调用ShowProcessedImage(m_nOperateID, bitmap);//传给函数,进行处理显示,//pictureBox1.Image = bitmap;//传给pictureBox1直接显示}}}m_objCFps.IncreaseFrameNum();}catch (Exception ex){MessageBox.Show(ex.Message);}
}

2 独立封装调用

2.1 获取图像宽、高、pBuffer、channel

        private void getImgInfo(IFrameData objIFrameData, ref IntPtr pBuffer){try{if (null != objIFrameData){//获取图像宽高SrcImgHeight = (int)objIFrameData.GetHeight();SrcImgWidth = (int)objIFrameData.GetWidth();//获取图像bufferGX_VALID_BIT_LIST emValidBits = GX_VALID_BIT_LIST.GX_BIT_0_7;emValidBits = __GetBestValudBit(objIFrameData.GetPixelFormat());// 判断图像是否成功接收if (GX_FRAME_STATUS_LIST.GX_FRAME_STATUS_SUCCESS == objIFrameData.GetStatus()){// 在关键部分的代码前加锁lock (this){if (colorFlag){// 彩色图像pBuffer = objIFrameData.ConvertToRGB24(emValidBits, GX_BAYER_CONVERT_TYPE_LIST.GX_RAW2RGB_NEIGHBOUR, false);//最后一个参数是否垂直翻转图像,true则翻转channel = 3;}else{// 黑白图像if (__IsPixelFormat8(objIFrameData.GetPixelFormat())){pBuffer = objIFrameData.GetBuffer();}else{pBuffer = objIFrameData.ConvertToRaw8(emValidBits);}channel = 1;}}}}}catch (Exception ex){MessageBox.Show(ex.Message);}}

2.2 内存图像数据截取ROI并显示

          private void getRoiBmpData(Rectangle ROI, IntPtr pBuffer, ref Bitmap ROI_bitmap){try{if (null != pBuffer){ //判断像素格式PixelFormat format = new PixelFormat();// format = channels == 3 ? PixelFormat.Format24bppRgb : PixelFormat.Format8bppIndexed;//若3通道彩色图像,否则黑白图像switch (channel){case 1:format = PixelFormat.Format8bppIndexed;break;case 3:format = PixelFormat.Format24bppRgb;break;case 4:format = PixelFormat.Format32bppArgb;break;}// 在关键部分的代码前加锁lock (this){//创建ROI 空图像Bitmap bitmap = new Bitmap(ROI.Width, ROI.Height, format);BitmapData bmpData = bitmap.LockBits(new Rectangle(0, 0, ROI.Width, ROI.Height), ImageLockMode.WriteOnly, bitmap.PixelFormat);int srcStride = SrcImgWidth * channel;// 原图每行数据长度int destStride = bmpData.Stride;// 新图每行数据长度int srcStartX = (ROI.X - 1) * channel; // ROI 起始 X 坐标在原图数据中的位置(二维视角)int srcStartY = ROI.Y - 1; // ROI 起始 Y 坐标在原图数据中的位置(二维视角)int srcOffset = srcStartY * srcStride + srcStartX; // ROI 起始位置在原图数据中的偏移量(原图数据在内存中是一行,一维数组)unsafe{byte* srcPtr = (byte*)pBuffer + srcOffset;byte* destPtr = (byte*)bmpData.Scan0;for (int y = 0; y < ROI.Height; y++){for (int x = 0; x < ROI.Width * channel; x++){destPtr[x] = srcPtr[x];}srcPtr += srcStride;destPtr += destStride;}}bitmap.UnlockBits(bmpData);// 在这里处理 bitmap 图像//ShowProcessedImage(m_nOperateID, bitmap);ROI_bitmap = bitmap;}}}catch (Exception ex){MessageBox.Show(ex.Message);}}

2.3 回调函数调用

public static int SrcImgHeight, SrcImgWidth;int channel = 0;bool isShowSrcImg = true;bool camImg_isProcess = false; //是否图像处理,不执行图像处理的时候,默认开启预览模式。bool isPreviewRoiImg = false; //是否图像处理,不执行图像处理的时候,默认开启预览模式。Rectangle ROI = new Rectangle(1323, 212, 2200, 1500);Bitmap bitmapB6;

代码中未出现的变量为 全局变量,或者库中的变量

        private void __OnFrameCallbackFun_1(object objUserParam, IFrameData objIFrameData){try{if (isShowSrcImg) //当开始处理图像时原视频要暂停,否则buffer中的数据会变化,图像上下颠倒交替出现(因Show(objIFrameData)中显示实现对图像数据做了垂直翻转){//************************************************************//显示相机获取的原图//************************************************************                 m_objGxBitmap1.Show(objIFrameData);}//获取图像宽、高、pBuffer、channel等信息getImgInfo2(objIFrameData, ref pBuffer1);//************************************************************// 对图像进行裁剪并显示在 PictureBox 中//*************************************************************if (isPreviewRoiImg)// 开启预览模式。{getRoiBmpData2(ROI, pBuffer1, ref bitmapB6);//ImageShow1.Image = bitmapB6;}//统计帧率m_objCFps1.IncreaseFrameNum();}catch (Exception ex){MessageBox.Show("回调函数2" + ex.Message);}}

3 for循环嵌套 方法2

        private void __OnFrameCallbackFun(object objUserParam, IFrameData objIFrameData){try{if (null != objIFrameData){// 获取图像信息int srcImgWidth = (int)objIFrameData.GetWidth();int srcImgHeight = (int)objIFrameData.GetHeight();GX_VALID_BIT_LIST emValidBits = GX_VALID_BIT_LIST.GX_BIT_0_7;emValidBits = __GetBestValudBit(objIFrameData.GetPixelFormat());// 判断图像是否成功接收if (GX_FRAME_STATUS_LIST.GX_FRAME_STATUS_SUCCESS == objIFrameData.GetStatus()){// 在关键部分的代码前加锁lock (this){IntPtr pBuffer = IntPtr.Zero;if (m_bIsColor){// 彩色图像pBuffer = objIFrameData.ConvertToRGB24(emValidBits, GX_BAYER_CONVERT_TYPE_LIST.GX_RAW2RGB_NEIGHBOUR, false);}else{// 黑白图像if (__IsPixelFormat8(objIFrameData.GetPixelFormat())){pBuffer = objIFrameData.GetBuffer();}else{pBuffer = objIFrameData.ConvertToRaw8(emValidBits);}}// 创建ROI BitmapBitmap bitmap = new Bitmap(ROI.Width, ROI.Height, PixelFormat.Format24bppRgb);BitmapData bmpData = bitmap.LockBits(new Rectangle(0, 0, ROI.Width, ROI.Height), ImageLockMode.WriteOnly, bitmap.PixelFormat);// 计算每行字节数int stride = bmpData.Stride;int bytes = Math.Abs(stride) * bitmap.Height;// 创建一个 byte 数组来存储图像数据byte[] imageData = new byte[bytes];// 计算ROI在原始图像中的偏移位置int roiOffsetX = ROI.X;int roiOffsetY = ROI.Y;// 将 pBuffer 中的图像数据复制到数组中,考虑ROI在原始图像中的偏移位置for (int y = 0; y < ROI.Height; y++){int srcY = roiOffsetY + y;int srcIndex = srcY * srcImgWidth * 3; // 假设是24位RGB图像for (int x = 0; x < ROI.Width; x++){int srcX = roiOffsetX + x;int dstIndex = (y * ROI.Width + x) * 3;imageData[dstIndex] = Marshal.ReadByte(pBuffer, srcIndex + srcX * 3);imageData[dstIndex + 1] = Marshal.ReadByte(pBuffer, srcIndex + srcX * 3 + 1);imageData[dstIndex + 2] = Marshal.ReadByte(pBuffer, srcIndex + srcX * 3 + 2);}}// 复制图像数据到 Bitmap 中Marshal.Copy(imageData, 0, bmpData.Scan0, bytes);bitmap.UnlockBits(bmpData);// 显示图像ShowProcessedImage(m_nOperateID, bitmap);}}}m_objCFps.IncreaseFrameNum();}catch (Exception ex){MessageBox.Show(ex.Message);}}

4 for循环嵌套 方法3

        private void __OnFrameCallbackFun(object objUserParam, IFrameData objIFrameData){try{if (null != objIFrameData){// 获取图像信息SrcImgWidth = (int)objIFrameData.GetWidth();SrcImgHeight = (int)objIFrameData.GetHeight();GX_VALID_BIT_LIST emValidBits = GX_VALID_BIT_LIST.GX_BIT_0_7;emValidBits = __GetBestValudBit(objIFrameData.GetPixelFormat());PixelFormat format;// 判断图像是否成功接收if (GX_FRAME_STATUS_LIST.GX_FRAME_STATUS_SUCCESS == objIFrameData.GetStatus()){// 在关键部分的代码前加锁lock (this){IntPtr pBuffer = IntPtr.Zero;int channel;if (m_bIsColor){// 彩色图像pBuffer = objIFrameData.ConvertToRGB24(emValidBits, GX_BAYER_CONVERT_TYPE_LIST.GX_RAW2RGB_NEIGHBOUR, false); // 最后一个参数是否垂直翻转图像,true则翻转channel = 3;}else{// 黑白图像if (__IsPixelFormat8(objIFrameData.GetPixelFormat())){pBuffer = objIFrameData.GetBuffer();}else{pBuffer = objIFrameData.ConvertToRaw8(emValidBits);}channel = 1;}// 判断像素格式format = channel == 3 ? PixelFormat.Format24bppRgb : PixelFormat.Format8bppIndexed;// 创建ROI 空图像m_bitmap = new Bitmap(ROI.Width, ROI.Height, format);BitmapData bmpData = m_bitmap.LockBits(new Rectangle(0, 0, ROI.Width, ROI.Height), ImageLockMode.WriteOnly, m_bitmap.PixelFormat);int srcStride = SrcImgWidth * channel; // 原图每行数据长度int destStride = bmpData.Stride;       // 新图每行数据长度int srcStartX = (ROI.X - 1) * channel; // ROI 起始 X 坐标在原图数据中的位置(二维视角)int srcStartY = ROI.Y - 1;             // ROI 起始 Y 坐标在原图数据中的位置(二维视角)int srcOffset = srcStartY * srcStride + srcStartX; // ROI 起始位置在原图数据中的偏移量(原图数据在内存中是一行,一维数组)// 将 pBuffer 中的图像数据复制到数组中,考虑ROI在原始图像中的偏移位置for (int y = 0; y < ROI.Height; y++){int srcY = srcStartY + y;int srcIndex = srcOffset + srcY * srcStride;for (int x = 0; x < ROI.Width * channel; x++){int srcX = srcStartX + x;int dstIndex = y * destStride + x;// 复制像素数据Marshal.WriteByte(bmpData.Scan0, dstIndex, Marshal.ReadByte(pBuffer, srcIndex + x));}}m_bitmap.UnlockBits(bmpData);// 显示图像ShowProcessedImage(m_nOperateID, m_bitmap);}}m_objCFps.IncreaseFrameNum();}}catch (Exception ex){MessageBox.Show(ex.Message);}}

5 按行复制数据提高效率,但很耗内存

        private unsafe void __OnFrameCallbackFun111(object objUserParam, IFrameData objIFrameData){try{if (null != objIFrameData){// 获取图像信息SrcImgWidth = (int)objIFrameData.GetWidth();SrcImgHeight = (int)objIFrameData.GetHeight();GX_VALID_BIT_LIST emValidBits = GX_VALID_BIT_LIST.GX_BIT_0_7;emValidBits = __GetBestValudBit(objIFrameData.GetPixelFormat());PixelFormat format;// 判断图像是否成功接收if (GX_FRAME_STATUS_LIST.GX_FRAME_STATUS_SUCCESS == objIFrameData.GetStatus()){// 在关键部分的代码前加锁lock (this){if (m_bIsColor){// 彩色图像pBuffer = objIFrameData.ConvertToRGB24(emValidBits, GX_BAYER_CONVERT_TYPE_LIST.GX_RAW2RGB_NEIGHBOUR, false); // 最后一个参数是否垂直翻转图像,true则翻转channel = 3;}else{// 黑白图像if (__IsPixelFormat8(objIFrameData.GetPixelFormat())){pBuffer = objIFrameData.GetBuffer();}else{pBuffer = objIFrameData.ConvertToRaw8(emValidBits);}channel = 1;}// 判断像素格式format = channel == 3 ? PixelFormat.Format24bppRgb : PixelFormat.Format8bppIndexed;// 创建ROI 空图像m_bitmap = new Bitmap(ROI.Width, ROI.Height, format);BitmapData bmpData = m_bitmap.LockBits(new Rectangle(0, 0, ROI.Width, ROI.Height), ImageLockMode.WriteOnly, m_bitmap.PixelFormat);int srcStride = SrcImgWidth * channel; // 原图每行数据长度  int destStride = bmpData.Stride;// 新图每行数据长度int srcStartX = (ROI.X - 1) * channel; // ROI 起始 X 坐标在原图数据中的位置(二维视角)      int srcStartY = ROI.Y - 1; // ROI 起始 Y 坐标在原图数据中的位置(二维视角)// ROI 起始位置在原图数据中的偏移量(原图数据在内存中是一行,一维数组)int srcOffset = srcStartY * srcStride + srcStartX;unsafe{// 计算 ROI 区域总字节数//int bytes = Math.Abs(destStride) * m_bitmap.Height;byte* bmpPtr = (byte*)bmpData.Scan0; // 指向 ROI Bitmap 的扫描行指针                        byte* srcPtr = (byte*)pBuffer + srcOffset;    // 指向原始图像数据的指针                         for (int y = 0; y < ROI.Height; y++)  // 逐行复制ROI区域的图像数据{// 复制当前行的图像数据到ROI Bitmap中//从源地址 srcPtr开始,每次复制destStride个字节(一整行的数据)到目标地址 bmpPtr 处,第四个参数偏移量Buffer.MemoryCopy(srcPtr, bmpPtr, destStride, destStride);bmpPtr += destStride;srcPtr += srcStride;}}m_bitmap.UnlockBits(bmpData);// 显示图像ShowProcessedImage(m_nOperateID, m_bitmap);}}m_objCFps.IncreaseFrameNum();}}catch (Exception ex){MessageBox.Show(ex.Message);}}

6 unsafe代码 解释及注意事项 看我另一篇文章

7 ConvertToRGB24详细解释 、示例、注意事项 看我另一篇文章

8 问题与反思

C# 自定义函数getRoiBmpData,该函数功能“对相机获取到的 IFrameData 转换为pBuffer ,然后进行ROI裁剪操作,将ROI图像bitmap传给ShowProcessedImage函数进行处理”。getRoiBmpData函数被5个回调函数同时调用,因为有5个相机,每个相机调用一个回调函数。那么我为什么5个相机要用5个回调呢,因为这样每个回调函数只负责一个相机,这样看起来分工更明确。

现在有两个问题:
问题1.这行代码“ Bitmap bitmap = new Bitmap(ROI.Width, ROI.Height, format);”中bitmap 被反复创建和使用,在该函数中需要手动释放吗?

问题2.这行代码“ Bitmap bitmap = new Bitmap(ROI.Width, ROI.Height, format);”中bitmap 被反复创建和使用,那么我可以创建一个全局变量Bitmap bitmap ,这样就不用每次进入函数都会创建一次bitmap ,但是呢我担心5个回调函数共享这一个bitmap 会冲突吗?当然ShowProcessedImage函数和getRoiBmpData函数也只有一个,都是同时被5个回调函数调用的。

8.1 被反复创建和使用,需手动释放吗?

在这段代码中,虽然 bitmap 被反复创建和使用,但在每次使用后都被正确地释放了。这是因为在使用完毕后调用了 bitmap.UnlockBits(bmpData); 来释放 BitmapData 对象。所以不需要手动释放 bitmap,因为在 bitmap 超出范围时会被自动回收。

bitmap 对象是在函数内部创建的,它会在函数执行完毕后自动离开作用域,从而被垃圾回收机制回收。因为它的生命周期受到函数作用域的限制,一旦函数执行完毕就会被销毁。

8.2 创建一个全局Bitmap bitma,多线程访问会冲突吗?

问题2:创建一个全局变量 Bitmap bitmap 是一种有效的方法,可以避免在每次函数调用时都重新创建 bitmap 对象。然而,如果多个回调函数同时访问和修改同一个全局 bitmap 对象,就可能会发生竞态条件或数据竞争,导致程序行为不确定或产生错误。因此,你需要确保在对 bitmap 进行读写操作时进行适当的线程同步,以避免冲突。

为了解决这个问题,可以采取以下方法之一

  • 在访问全局 bitmap 对象时使用线程同步机制(如锁),以确保在任何时候只有一个回调函数可以访问或修改 bitmap 对象。这样可以避免并发访问导致的问题。一个简单的方法是在访问 bitmap 之前使用 lock 关键字来确保线程安全,就像你在代码中对关键部分加锁一样。这样可以确保每次只有一个线程能够访问 bitmap,从而避免并发冲突。

  • 将 bitmap 对象作为函数参数传递给每个回调函数,这样每个函数都有自己的 bitmap 对象实例,不会相互干扰。

选择哪种方法取决于你的具体需求和代码结构。如果需要在多个回调函数之间共享相同的 bitmap 对象,并且需要确保线程安全,则使用第一种方法;如果每个回调函数都需要独立的 bitmap 对象,则使用第二种方法。

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

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

ubuntu22.04系统入门 linux入门(二) 简单命令 多实践以及相关文件管理命令

以下有免费的4090云主机提供ubuntu22.04系统的其他入门实践操作 地址&#xff1a;星宇科技 | GPU服务器 高性能云主机 云服务器-登录 相关兑换码星宇社区---4090算力卡免费体验、共享开发社区-CSDN博客 之所以推荐给大家使用&#xff0c;是因为上面的云主机目前是免费使用的…

分布式ID方案(标记)

一、参考文章-标记 分布式ID方案有哪些&#xff1f;雪花算法如何搞定时钟回拨和动态机器ID&#xff1f; 二、应用 1.百度 uid-generator github项目地址 原理参考 2.百度 uid-generator 扩展应用 灯官网 灯 项目代码 lamp-util 单元模块 lamp-util 单元模块子模块 lamp-…

std::map 加锁

在并发环境下使用std::map&#xff0c;必须采取同步措施。 在并发环境下对 std::map 进行不加锁的读写操作会导致严重的线程安全问题&#xff0c;主要会产生以下几种问题&#xff1a; ⚠️ 主要风险与后果数据竞争&#xff08;Data Race&#xff09; 当多个线程同时修改同一个键…

学习笔记090——Ubuntu 中 UFW 防火墙的使用

文章目录1、允许特定的端口访问2、允许特定 IP 访问某个端口3、允许某个范围的端口4、查看 UFW 状态5、重新加载 UFW6、启用 UFW7、关闭 UFW1、允许特定的端口访问 # 允许 TCP 端口&#xff08;例如 80&#xff09;&#xff1a; sudo ufw allow 80/tcp# 允许 UDP 端口&#xf…

移动端 WebView 内存泄漏与性能退化问题如何排查 实战调试方法汇总

在混合 App 应用中&#xff0c;WebView 页面常承载复杂业务逻辑与交互。随着用户使用时间增长&#xff0c;特别在切换多个页面或反复打开界面后&#xff0c;常常会出现性能下降、页面卡顿、甚至白屏崩溃等现象。这通常是因为页面存在内存泄漏、事件监听未解绑或垃圾回收阻塞导致…

JSON 对象在浏览器中顺序与后端接口返回不一致的问题

一、问题描述 后端接口返回一个字典表的JSON对象&#xff0c;页面展示排序与预期排序不一致。 在浏览器调试面板Response中看到接口原始响应字符串&#xff0c;是期望顺序&#xff1a;在Preview中看到&#xff0c; key “22” 被提到最前&#xff0c;顺序发生变化&#xff1a;页…

Spring MVC数据传递全攻略

Spring MVC数据传递一、前端到后端的数据传递1. 使用 RequestParam 传递简单参数2. 使用 PathVariable传递路径参数3. 使用RequestBody传递 JSON 数据二、后端到前端的数据传递1. 使用Model或 ModelAndView传递数据到前端2. 使用HttpServletResponse直接写回数据3.使用Response…

仓库管理系统-12-前端之头部区域Header基于嵌套路由访问个人中心

文章目录 1 个人中心 1.1 DateUtils.vue(子组件) 1.2 Home.vue(父组件) 1.3 router/index.js(嵌套路由) 1.4 index.vue(路由占位符) 2 Header.vue 2.1 页面布局 2.2 toUser方法 2.3 初始加载 2.4 Header.vue 头部区域Header中有一个个人中心下拉菜单,点击个人中心选项,通过嵌…

【智能协同云图库】第七期:基于AI调用阿里云百炼大模型,实现AI图片编辑功能

摘要&#xff1a;AI 高速发展赋能传统业务&#xff0c;图库网站亦有诸多 AI 应用空间。以 AI 扩图功؜能为例&#xff0c;让我们来学习如何在项目⁠中快速接入 AI 绘图大模型。‏用户可以选择一张已上传的图片&#xff0c;‌通过 AI 扩图得到新的图片&#xff0c;希望可以帮到大…

Notepad++插件安装

方式一&#xff1a;自动安装&#xff08;有些notepad并不好用&#xff0c;推荐方式二&#xff09;工具栏-》插件-》插件管理如下点击安装后会提示&#xff0c;后端安装&#xff0c;安装成功后自动启动&#xff0c;本人使用的v8.6.4的版本&#xff0c;插件基本都无法自动安装&am…

git pull和git fetch的区别

git pull和git fetch是git版本控制系统中的两个基本命令&#xff0c;它们都用于从远程仓库更新本地仓库的信息&#xff0c;但执行的具体操作不同。git fetch:git fetch下载远程仓库最新的内容到你的本地仓库&#xff0c;但它并不自动合并或修改你当前的工作。它取回了远程仓库的…

Item35:考虑virtual函数以外的其他选择

在C++中,虚函数是实现多态的传统方式,但并非唯一选择。过度依赖虚函数可能导致派生类与基类的强耦合,或难以在运行时灵活切换行为。《Effective C++》Item35指出:应根据场景选择更合适的替代方案,包括NVI模式、函数指针、策略模式等。本文解析这些方案的原理、适用场景及实…

Vue3 状态管理新选择:Pinia 从入门到实战

一、什么是pinia? 在 Vue3 生态中&#xff0c;状态管理一直是开发者关注的核心话题。随着 Vuex 的逐步淡出&#xff0c;Pinia 作为官方推荐的状态管理库&#xff0c;凭借其简洁的 API、强大的功能和对 Vue3 特性的完美适配&#xff0c;成为了新时代的不二之选。今天我们就来深…

Unity相机控制

相机的控制无非移动和旋转&#xff0c;每种操作各3个轴6个方向&#xff0c;一共12种方式。在某些需要快速验证的项目或Demo里常常需要丝滑的控制相机调试效果。相机控制虽然不是什么高深的技术&#xff0c;但是要写的好用还是很磨人的。 锁定Z轴的旋转 一个自由的相机可以绕 …

vue2 使用liveplayer加载视频

vue2 使用liveplayer加载视频 官网: https://www.liveqing.com/docs/manuals/LivePlayer.html支持WebRTC/MP4播放;支持m3u8/HLS播放;支持HTTP-FLV/WS-FLV/RTMP播放;支持直播和点播播放;支持播放器快照截图;支持点播多清晰度播放;支持全屏或比例显示;自动检测IE浏览器兼容播放;支…

JavaScript语法树简介:AST/CST/词法/语法分析/ESTree/生成工具

AST简介 在平时的开发中&#xff0c;经常会遇到对JavaScript代码进行检查或改动的工具&#xff0c;例如ESLint会检查代码中的语法错误&#xff1b;Prettier会修改代码的格式&#xff1b;打包工具会将不同文件中的代码打包在一起等等。这些工具都对JavaScript代码本身进行了解析…

Java函数式编程之【基本数据类型流】

一、基本数据类型与基本数据的包装类 在Java编程语言中&#xff0c;int、long和double等基本数据类型都各有它们的包装类型Integer、Long和Double。 基本数据类型是Java程序语言内置的数据类型&#xff0c;可直接使用。 而包装类型则归属于普通的Java类&#xff0c;是对基本数据…

.NET Core部署服务器

1、以.NET Core5.0为例&#xff0c;在官网下载 下载 .NET 5.0 (Linux、macOS 和 Windows) | .NET 根据自己需求选择x64还是x86&#xff0c;记住关键下载完成还需要下载 Hosting Bundel &#xff0c;否则不成功 2、部署https将ssl证书放在服务器上&#xff0c;双击导入&#…

YOLO---04YOLOv3

YOLOV3 论文地址&#xff1a;&#xff1a;【https://arxiv.org/pdf/1804.02767】 YOLOV3 论文中文翻译地址&#xff1a;&#xff1a;【YOLO3论文中文版_yolo v3论文 中文版-CSDN博客】 YOLOv3 在实时性和精确性在当时都是做的比较好的&#xff0c;并在工业界得到了广泛应用 …

Qt知识点3『自定义属性的样式表失败问题』

问题1&#xff1a;自定义类中的自定义属性&#xff0c;如何通过样式表来赋值除了QT自带的属性&#xff0c;我们自定义的类中如果有自定义的静态属性&#xff0c;也可以支持样式表&#xff0c;如下 &#xff1a; Q_PROPERTY(QColor myBorderColor READ getMyBorderColor WRITE s…