当前位置: 首页 > news >正文

【13】大恒相机SDK C#开发 —— Fom1中实时处理的8个图像 实时显示在Form2界面的 pictureBox中

文章目录

  • 1 问题描述
  • 1 Form2调用Form1的公共Bitmap——显示
    • 1.1 Form1代码实现
    • 1.2 Form2代码实现
  • 2 使用事件触发
    • 2.1 Form1 代码实现
    • 2.2 Form2代码实现

1 问题描述

在主界面 Form1中,多个相机采集的图像 经过处理后,实时显示 在Form2界面的 pictureBox中;共有8个区域的图像要实时显示。

此功能以下称为预览模式,Form1在代码中命名为 TestApp,Form2在代码中其实是两Form分别命名为PreviewLPreviewR。(实际使用中8个图像,一个屏幕预览效果不好,分成了两个屏幕预览。左屏4个预览画面,右屏4个预览画面)
下面是显示左屏4个区域的预览实现

1 Form2调用Form1的公共Bitmap——显示

1.1 Form1代码实现

在Form1声明8个 public static Bitmap:

  public static Bitmap bitmapB6, bitmapC6, bitmapB5, bitmapB4, bitmapC4, bitmapB3, bitmapB2, bitmapC2, bitmapF6, bitmapF2;

在回调函数中获取8个区域的图像,

下面是bitmapB6,bitmapC6获取的示例。

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

启动Form2,显示预览画面

   private void bt_Preview_Click(object sender, EventArgs e){isPreviewRoiImg = true;//预览窗口实例化,并显示PreviewL previewL = new PreviewL();PreviewR previewR = new PreviewR();previewL.Show();            previewR.Show();Thread.Sleep(500);//按键使能bt_Preview.Enabled = false;}

其中的 getRoiBmpData函数

        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);}}

1.2 Form2代码实现

(实际使用中8个图像,一个屏幕预览效果不好,分成了两个屏幕预览。左屏4个预览画面,右屏4个预览画面)
下面是显示左屏4个区域的预览实现

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Timers;
using System.Windows.Forms;
using static TestAppMain.TestApp;namespace TestAppMain
{public partial class PreviewL : Form{//private System.Timers.Timer timer;//private System.Threading.Timer timer;//在这个案例中,使用 System.Windows.Forms.Timer,因为它是与 Windows 窗体应用程序兼容的计时器。它可以在 UI 线程上执行操作,因此更适合在窗体中刷新图像等 UI 相关的操作。private System.Windows.Forms.Timer timer;public PreviewL(){InitializeComponent();fullScreen();// 创建一个定时器,每隔一定时间刷新图像timer = new System.Windows.Forms.Timer();timer.Interval = 100; // 设置刷新间隔为100毫秒(可以根据需要调整)timer.Tick += Timer_Tick;timer.Start();}private void fullScreen(){// 判断当前窗体是否已经是最大化状态if (this.WindowState == FormWindowState.Maximized){// 如果已经最大化,则恢复到正常状态this.WindowState = FormWindowState.Normal;}else{// 如果不是最大化,则将窗体最大化this.WindowState = FormWindowState.Maximized;}}private void Timer_Tick(object sender, EventArgs e){// 在定时器触发事件中刷新图像RefreshPreview();}private void RefreshPreview(){// 更新PictureBox中显示的图像pictureBox_B6.Image = bitmapB6;pictureBox_B5.Image = bitmapB5;pictureBox_C6.Image = bitmapC6;pictureBox_C4.Image = bitmapC4;}protected override void OnClosed(EventArgs e){base.OnClosed(e);// 关闭窗口时停止定时器timer.Stop();timer.Dispose();}}
}

因为定义个了8个全局公共变量的图像,浪费资源,下面是事件函数实现;

2 使用事件触发

因为定义个了8个全局公共变量的图像,浪费资源,下面是事件函数实现;

2.1 Form1 代码实现

在Form1中声明一个枚举变量,把需要显示的8个区域 放在枚举中。定义事件函数和方法;

using GxIAPINET;
using MaterialSkin.Controls;
using System;
using System.Drawing;
using System.Windows.Forms;namespace TestAppMain
{//枚举类型声明public enum enum_ImgRegion{//cam1B6, C6,//cam2B4, C4, B5,//cam3B2, C2, B3,//cam4F6, E6,//cam5F2, E2};public partial class TestApp : Form{//From1主界面,这里Form1命名为TestApp// 定义事件---使回调中的图像在另一个form中显示public static event EventHandler<ImageEventArgs> ImageProcessed;// 在图像处理回调函数中调用该方法,参数为相机编号和处理后的图像public static void ShowProcessedImage(enum_ImgRegion imgRegion, Bitmap bitmap){// 触发图像处理完成事件ImageProcessed?.Invoke(null, new ImageEventArgs(imgRegion, bitmap));}public TestApp(){InitializeComponent();}////其他函数////回调使用private void __OnFrameCallbackFun_1(object objUserParam, IFrameData objIFrameData){try{if (isShowSrcImg) //当开始处理图像时原视频要暂停,否则buffer中的数据会变化,图像上下颠倒交替出现(因Show(objIFrameData)中显示实现对图像数据做了垂直翻转){//************************************************************//显示相机获取的原图//************************************************************                 m_objGxBitmap1.Show(objIFrameData);}//获取图像宽、高、pBuffer、channel等信息getImgInfo(objIFrameData, ref pBuffer1);//************************************************************// 对图像进行裁剪并显示在 PictureBox 中//*************************************************************if (isPreviewRoiImg)// 开启预览模式。{getRoiBmpData(ROI_B6, pBuffer1, enum_ImgRegion.B6);getRoiBmpData(ROI_C6, pBuffer1, enum_ImgRegion.C6);}//统计帧率m_objCFps1.IncreaseFrameNum();}catch (Exception ex){MessageBox.Show("回调函数2" + ex.Message);}}//其他回调函数函数//启动Form2,显示预览画面private void bt_Preview_Click(object sender, EventArgs e){isPreviewRoiImg = true;//预览窗口实例化,并显示PreviewL previewL = new PreviewL();PreviewR previewR = new PreviewR();previewL.Show();            previewR.Show();Thread.Sleep(500);//按键使能bt_Preview.Enabled = false;}}//定义事件类,注意要 TestApp同级别,也就是都在namespace TestAppMain命名空间下的同一个级别public class ImageEventArgs : EventArgs{public enum_ImgRegion ImgRegion { get; }public Bitmap ProcessedImage { get; }public ImageEventArgs(enum_ImgRegion imgRegion, Bitmap processedImage){ImgRegion = imgRegion;ProcessedImage = processedImage;}}
}

代码中的 getRoiBmpData函数,该函数与方法1中的函数一样,只是入口参数做了更改。

        //方法法①双循环逐字节复制ROI区域的图像数据;//方法②单循环, 逐行复制ROI区域的图像数据,提高效率,但很耗内存;private void getRoiBmpData(Rectangle ROI, IntPtr pBuffer, enum_ImgRegion imgRegion){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{//int bytes = Math.Abs(destStride) * m_bitmap.Height;     // 计算 ROI 区域总字节数                                   byte* srcPtr = (byte*)pBuffer + srcOffset;    // 指向原始图像数据的指针(获取位图数据的起始地址,并将其转换为 byte* 类型的指针。bmpData.Scan0 返回的是位图数据的第一个像素的内存地址)byte* destPtr = (byte*)bmpData.Scan0; // 指向 ROI Bitmap 的扫描行指针   ////双循环,逐字节操作;//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;//}//单循环, 逐行操作for (int y = 0; y < ROI.Height; y++)  // 逐行复制ROI区域的图像数据{// 复制当前行的图像数据到ROI Bitmap中//从源地址 srcPtr开始,每次复制destStride个字节(一整行的数据)到目标地址 bmpPtr 处,第四个参数偏移量Buffer.MemoryCopy(srcPtr, destPtr, destStride, destStride);destPtr += destStride;srcPtr += srcStride;}}//解锁对位图数据的访问,使其能够被其他代码访问。释放与位图数据关联的内存区域,以便系统能够对其进行管理。bitmap.UnlockBits(bmpData);// 在这里处理 bitmap 图像ShowProcessedImage(imgRegion, bitmap);//传给函数,进行处理显示,                      //ROI_bitmap = bitmap;}}}catch (Exception ex){MessageBox.Show(ex.Message);}}

2.2 Form2代码实现

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Timers;
using System.Windows.Forms;
using static TestAppMain.TestApp;namespace TestAppMain
{public partial class PreviewL : Form{public PreviewL(){InitializeComponent();//InitializeLayout();fullScreen();// 订阅图片处理事件TestApp.ImageProcessed += ImageShowFrom_ImageProcessed;}private void fullScreen(){// 判断当前窗体是否已经是最大化状态if (this.WindowState == FormWindowState.Maximized){// 如果已经最大化,则恢复到正常状态this.WindowState = FormWindowState.Normal;}else{// 如果不是最大化,则将窗体最大化this.WindowState = FormWindowState.Maximized;}}// 图片处理事件处理程序private void ImageShowFrom_ImageProcessed(object sender, ImageEventArgs e){switch (e.ImgRegion){case enum_ImgRegion.B6:pictureBox_B6.Image = e.ProcessedImage;break;case enum_ImgRegion.B5:pictureBox_B5.Image = e.ProcessedImage;break;case enum_ImgRegion.C6:pictureBox_C6.Image = e.ProcessedImage;break;case enum_ImgRegion.C4:pictureBox_C4.Image = e.ProcessedImage;break;default:break;}}}
}
http://www.lryc.cn/news/605482.html

相关文章:

  • 磁盘坏道检测工具在美国服务器硬件维护中的使用规范
  • MVS相机+YOLO检测方法
  • 【03】大恒相机SDK C#开发 —— 回调采集图像,关闭相机
  • Java WEB技术-序列化和反序列化认识(SpringBoot的Jackson序列化行为?如何打破序列化过程的驼峰规则?如何解决学序列化循环引用问题?)
  • 学习笔记《区块链技术与应用》第三天 网络 难度
  • 详解分布式数据库缓存技术:高性能数据访问的基石
  • 如何在 macOS 上使用 dnsmasq 搭建本地 DNS 缓存/转发
  • 深度解析:基于Python构建的闲鱼自动化营销与信息发送机器人
  • IO流专题
  • linux运维学习第十三周
  • Linux 服务器性能优化:性能监控,系统性能调优,进程优先级,内核升级全解析
  • 前端框架Vue3(二)——Vue3核心语法之OptionsAPI与CompositionAPI与setup
  • AWS云安全审计终极实战指南:构建自动化安全防线
  • 数字化应急预案:构筑现代安全防线
  • Web3:在 VSCode 中使用 Vue 前端与已部署的 Solidity 智能合约进行交互
  • 从渠道渗透到圈层渗透:开源链动2+1模式、AI智能名片与S2B2C商城小程序的协同创新路径研究
  • 【09】大恒相机SDK C#开发 ——库函数 IntPtr ConvertToRGB24详细解释 及 示例
  • 【JEECG】JVxeTable表格拖拽排序功能
  • 动态规划Day5学习心得
  • python的异步、并发开发
  • (C++)C++类和类的方法(基础教程)(与Python类的区别)
  • C++提高编程学习--模板
  • 【硬件-笔试面试题】硬件/电子工程师,笔试面试题-50,(知识点:TCP/IP 模型)
  • 磁盘IO优先级控制对美国服务器存储子系统的调优验证
  • 02 基于sklearn的机械学习-KNN算法、模型选择与调优(交叉验证、朴素贝叶斯算法、拉普拉斯平滑)、决策树(信息增益、基尼指数)、随机森林
  • 【动态规划 | 多状态问题】动态规划求解多状态问题
  • YOLO---01目标检测基础
  • windows环境下MySQL 8.0 修改或重置密码
  • Mybatis分页查询当前页数据条数大于实际返回的数据条数
  • 7.5将模块分离到不同的文件中