折腾笔记[36]-调用海康SDK实现相机拍照

news/2025/11/9 19:25:05/文章来源:https://www.cnblogs.com/qsbye/p/19204722

摘要

使用c#调用海康SDK实现相机拍照.

前言

本文目的是分享人工踩坑经验, AI搜索引擎可以更快给出正确结果(用于投喂AI😂).

关键信息

  • 海康SDK版本: 4.6.x
  • .net8框架
  • 封装: HikVisionCom
  • 测试序列号:"00DA4347368"
  • dll文件位置1: C:\Program Files (x86)\Common Files\MVS\Runtime\Win64_x64\MvCameraControl.dll
  • dll文件位置2: C:\Program Files (x86)\MVS\Applications\Win64
  • kernel32.dll(用Everything.exe软件搜索)

实现

文件

PS W:\Lab\exp42-hikvision-conn\CamTest\libs> tree.com /f
文件夹 PATH 列表
卷序列号为 099D-E17A
W:.
│  Grab_Callback.exe
│  GrabImage.exe
│  kernel32.dll
│  libmmd.dll
│  Microsoft.VC90.CRT.manifest
│  Microsoft.VC90.DebugCRT.manifest
│  msvcm90.dll
│  msvcp90.dll
│  msvcr90.dll
│  msvcr120.dll
│  MVAIndustryControl.dll
│  MVARenderWidget.dll
│  MVCameraSDK.csproj
│  MVCameraSDK.sln
│  MVCameraSDK.snk
│  MVCameraSDK_net8.csproj
│  MvCamLVision.dll
│  MvDSS.ax
│  MvDSS2.ax
│  MVFGControl.dll
│  MvFGProducerCML.cti
│  MvFGProducerCXP.cti
│  MvFGProducerGEV.cti
│  MvFGProducerXoF.cti
│  MvFrameGrabberControl.dll
│  MVGigEVisionSDK.dll
│  MvISPControl.dll
│  MvLCProducer.dll
│  MVMemAlloc.dll
│  MvProducerGEV.cti
│  MvProducerU3V.cti
│  MvProducerVIR.dll
│  MvRender.dll
│  MvSDKVersion.dll
│  MvSerial.dll
│  MvSerialCtrl.dll
│  MvUsb3vTL.dll
│  NetworkAdapterCfgLib.dll
│  NetworkAdapterCfgLib_NIC.dll
│  ParametrizeCamera_AreaScanIOSettings.exe
│  ParametrizeCamera_LineScanIOSettings.exe
│  qwt.dll
│  ScreenPoint.dll
│  BasicDemo.exe
│  CommonTools.dll
│  ConvertPixelType.exe
│  CustomCtr.dll
│  DeviceEnumMng.dll
│  MvCameraControl.Net.dll
│  MvCameraControl.Net.xml
│  MvCameraControl.dll
│  CommonParameters.ini
│  D3DCompiler_43.dll
│  d3dcompiler_47.dll
│  d3dx9_43.dll
│  FormatConversion.dll
│  GCBase_MD_VC120_v3_0_MV.dll
│  GenApi_MD_VC120_v3_0_MV.dll
│  libusb0.dll
│  Log_MD_VC120_v3_0_MV.dll
│  log4cpp_MD_VC120_v3_0_MV.dll
│  MathParser_MD_VC120_v3_0_MV.dll
│  MediaProcess.dll
│  msvcp120.dll
│  msvcr100.dll
│  MvCameraControlGUI.dll
│  MvCameraControlWrapper.dll
│  MvCameraPatch.dll
│  NodeMapData_MD_VC120_v3_0_MV.dll
│  pthreadGC2.dll
│  pthreadVC2.dll
│  SuperRender.dll
│  svml_dispmd.dll
│  XmlParser_MD_VC120_v3_0_MV.dll
│  CLAllSerial_MD_VC120_v3_0_MV.dll
│  CLProtocol_MD_VC120_v3_0_MV.dll
│  CLSerCOM.dll
│  CLSerHvc.dll
│
└─ThirdPartyavutil-57.dlllibwinpthread-1.dllswscale-6.dll

官方示例

# 创建C#工程,在工程中将MVCAM_COMMON_RUNENV\DotNet\AnyCpu路径下的MvCamCtrl.Net.dIl添加到工程引用中,MVCAM_COMMON_RUNENV即为PC环境变量
echo $env:MVCAM_COMMON_RUNENV
$env:MVCAM_COMMON_RUNENV
dotnet new classlib -n HikVisionCom -f net8.0
cd HikVisionCom# 也可以通过nuget包方式直接添加引用
dotnet add package MvCameraControl.Nettree.com /f

官方示例(枚举设备、连接设备、获取图像):
GrabImage.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using MvCamCtrl.NET;
using System.Runtime.InteropServices;
using System.IO;
using System.Threading;namespace GrabImage
{class GrabImage{static bool g_bExit = false;public static void ReceiveImageWorkThread(object obj){int nRet = MyCamera.MV_OK;MyCamera device = obj as MyCamera;MyCamera.MV_FRAME_OUT stImageOut = new MyCamera.MV_FRAME_OUT();while (true){nRet = device.MV_CC_GetImageBuffer_NET(ref stImageOut, 1000);if (nRet == MyCamera.MV_OK){Console.WriteLine("Get Image Buffer:" + "Width[" + Convert.ToString(stImageOut.stFrameInfo.nWidth) + "] , Height[" + Convert.ToString(stImageOut.stFrameInfo.nHeight)+ "] , FrameNum[" + Convert.ToString(stImageOut.stFrameInfo.nFrameNum) + "]");device.MV_CC_FreeImageBuffer_NET(ref stImageOut);}else{Console.WriteLine("Get Image failed:{0:x8}", nRet);}if (g_bExit){break;}}}static void Main(string[] args){int nRet = MyCamera.MV_OK;// ch: 初始化 SDK | en: Initialize SDKMyCamera.MV_CC_Initialize_NET();MyCamera device = new MyCamera();do{// ch:枚举设备 | en:Enum deviceMyCamera.MV_CC_DEVICE_INFO_LIST stDevList = new MyCamera.MV_CC_DEVICE_INFO_LIST();nRet = MyCamera.MV_CC_EnumDevices_NET(MyCamera.MV_GIGE_DEVICE | MyCamera.MV_USB_DEVICE, ref stDevList);if (MyCamera.MV_OK != nRet){Console.WriteLine("Enum device failed:{0:x8}", nRet);break;}Console.WriteLine("Enum device count : " + Convert.ToString(stDevList.nDeviceNum));if (0 == stDevList.nDeviceNum){break;}MyCamera.MV_CC_DEVICE_INFO stDevInfo;                            // 通用设备信息// ch:打印设备信息 en:Print device infofor (Int32 i = 0; i < stDevList.nDeviceNum; i++){stDevInfo = (MyCamera.MV_CC_DEVICE_INFO)Marshal.PtrToStructure(stDevList.pDeviceInfo[i], typeof(MyCamera.MV_CC_DEVICE_INFO));if (MyCamera.MV_GIGE_DEVICE == stDevInfo.nTLayerType){MyCamera.MV_GIGE_DEVICE_INFO_EX stGigEDeviceInfo = (MyCamera.MV_GIGE_DEVICE_INFO_EX)MyCamera.ByteToStruct(stDevInfo.SpecialInfo.stGigEInfo, typeof(MyCamera.MV_GIGE_DEVICE_INFO_EX));uint nIp1 = ((stGigEDeviceInfo.nCurrentIp & 0xff000000) >> 24);uint nIp2 = ((stGigEDeviceInfo.nCurrentIp & 0x00ff0000) >> 16);uint nIp3 = ((stGigEDeviceInfo.nCurrentIp & 0x0000ff00) >> 8);uint nIp4 = (stGigEDeviceInfo.nCurrentIp & 0x000000ff);Console.WriteLine("[device " + i.ToString() + "]:");Console.WriteLine("DevIP:" + nIp1 + "." + nIp2 + "." + nIp3 + "." + nIp4);Console.WriteLine("ModelName:" + stGigEDeviceInfo.chModelName + "\n");}else if (MyCamera.MV_USB_DEVICE == stDevInfo.nTLayerType){MyCamera.MV_USB3_DEVICE_INFO_EX stUsb3DeviceInfo = (MyCamera.MV_USB3_DEVICE_INFO_EX)MyCamera.ByteToStruct(stDevInfo.SpecialInfo.stUsb3VInfo, typeof(MyCamera.MV_USB3_DEVICE_INFO_EX));Console.WriteLine("[device " + i.ToString() + "]:");Console.WriteLine("SerialNumber:" + stUsb3DeviceInfo.chSerialNumber);Console.WriteLine("ModelName:" + stUsb3DeviceInfo.chModelName + "\n");}}Int32 nDevIndex = 0;Console.Write("Please input index(0-{0:d}):", stDevList.nDeviceNum - 1);try{nDevIndex = Convert.ToInt32(Console.ReadLine());}catch{Console.Write("Invalid Input!\n");break;}if (nDevIndex > stDevList.nDeviceNum - 1 || nDevIndex < 0){Console.Write("Input Error!\n");break;}stDevInfo = (MyCamera.MV_CC_DEVICE_INFO)Marshal.PtrToStructure(stDevList.pDeviceInfo[nDevIndex], typeof(MyCamera.MV_CC_DEVICE_INFO));// ch:创建设备 | en:Create devicenRet = device.MV_CC_CreateDevice_NET(ref stDevInfo);if (MyCamera.MV_OK != nRet){Console.WriteLine("Create device failed:{0:x8}", nRet);break;}// ch:打开设备 | en:Open devicenRet = device.MV_CC_OpenDevice_NET();if (MyCamera.MV_OK != nRet){Console.WriteLine("Open device failed:{0:x8}", nRet);break;}// ch:探测网络最佳包大小(只对GigE相机有效) | en:Detection network optimal package size(It only works for the GigE camera)if (stDevInfo.nTLayerType == MyCamera.MV_GIGE_DEVICE){int nPacketSize = device.MV_CC_GetOptimalPacketSize_NET();if (nPacketSize > 0){nRet = device.MV_CC_SetIntValueEx_NET("GevSCPSPacketSize", nPacketSize);if (nRet != MyCamera.MV_OK){Console.WriteLine("Warning: Set Packet Size failed {0:x8}", nRet);}}else{Console.WriteLine("Warning: Get Packet Size failed {0:x8}", nPacketSize);}}// ch:设置触发模式为off || en:set trigger mode as offif (MyCamera.MV_OK != device.MV_CC_SetEnumValue_NET("TriggerMode", 0)){Console.WriteLine("Set TriggerMode failed:{0:x8}", nRet);break;}// ch:开启抓图 | en:start grabnRet = device.MV_CC_StartGrabbing_NET();if (MyCamera.MV_OK != nRet){Console.WriteLine("Start grabbing failed:{0:x8}", nRet);break;}Thread hReceiveImageThreadHandle = new Thread(ReceiveImageWorkThread);hReceiveImageThreadHandle.Start(device);Console.WriteLine("Press enter to exit");Console.ReadKey();g_bExit = true;Thread.Sleep(1000);// ch:停止抓图 | en:Stop grab imagenRet = device.MV_CC_StopGrabbing_NET();if (MyCamera.MV_OK != nRet){Console.WriteLine("Stop grabbing failed:{0:x8}", nRet);break;}// ch:关闭设备 | en:Close devicenRet = device.MV_CC_CloseDevice_NET();if (MyCamera.MV_OK != nRet){Console.WriteLine("Close device failed:{0:x8}", nRet);break;}// ch:销毁设备 | en:Destroy devicenRet = device.MV_CC_DestroyDevice_NET();if (MyCamera.MV_OK != nRet){Console.WriteLine("Destroy device failed:{0:x8}", nRet);break;}} while (false);if (MyCamera.MV_OK != nRet){// ch:销毁设备 | en:Destroy devicenRet = device.MV_CC_DestroyDevice_NET();if (MyCamera.MV_OK != nRet){Console.WriteLine("Destroy device failed:{0:x8}", nRet);}}// ch: 反初始化SDK | en: Finalize SDKMyCamera.MV_CC_Finalize_NET();Console.WriteLine("Press enter to exit");Console.ReadKey();}}
}

封装

配置:

<Project Sdk="Microsoft.NET.Sdk"><PropertyGroup><!-- <OutputType>Exe</OutputType> --><OutputType>Library</OutputType><TargetFramework>net8.0</TargetFramework><ImplicitUsings>enable</ImplicitUsings><Nullable>enable</Nullable></PropertyGroup><PropertyGroup><!-- 目标框架 --><TargetFramework>net8.0</TargetFramework><!-- 对外 COM 可见 --><ComVisible>true</ComVisible><EnableComHosting>true</EnableComHosting><EnableRegFreeCom>true</EnableRegFreeCom><!-- 注册 COM 时用的 GUID(可选) --><Guid>b2c3d4e5-f6a7-4b5c-8d9e-0f1a2b3c4d5e</Guid><!-- 关键:允许不安全代码 --><AllowUnsafeBlocks>true</AllowUnsafeBlocks><!-- 让输出目录始终为 bin\<Configuration>\net8.0\ --><AppendTargetFrameworkToOutputPath>true</AppendTargetFrameworkToOutputPath></PropertyGroup><ItemGroup><Reference Include="System.Drawing.Common"><HintPath>libs\System.Drawing.Common.dll</HintPath></Reference></ItemGroup><!-- 把 libs 里所有 dll 拷到输出目录 --><Target Name="CopyLibs" AfterTargets="Build"><ItemGroup><NativeLibs Include="$(MSBuildProjectDirectory)\libs\*" /></ItemGroup><Copy SourceFiles="@(NativeLibs)" DestinationFolder="$(TargetDir)" SkipUnchangedFiles="true" OverwriteReadOnlyFiles="true" /></Target></Project>

封装代码:

// 文件: HikVisionCom.cs
// 功能: 对外COM接口// 标准库
using System;
// using System.Drawing.Common;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Runtime.InteropServices;
using System.Threading;
using System.Threading.Tasks;// 海康库
using MvCamCtrl.NET;namespace HikVisionCom
{[ComVisible(true)][Guid("EAA0C3F7-8D07-4EF1-B7A4-CE31F1A7DC2E")][InterfaceType(ComInterfaceType.InterfaceIsDual)]public interface IHikCamera{void Init(string serial);void Connect();void Disconnect();string Shot(int exposure = 13000, float gain = 1f);void StartStream(int exposure = 13000, float gain = 1f);void StopStream();bool IsStreaming { get; }}[ComVisible(true)][Guid("0B3C3297-0D91-4A98-9C52-BB9E3CE4728F")][ClassInterface(ClassInterfaceType.None)]public class HikCamera : IHikCamera{private MyCamera _cam = new();private MyCamera.MV_CC_DEVICE_INFO _info;private bool _open;private bool _grab;private Task _streamTask;private CancellationTokenSource _cts;private readonly object _lock = new();public void Init(string serial){MyCamera.MV_CC_Initialize_NET();var list = new MyCamera.MV_CC_DEVICE_INFO_LIST();int ret = MyCamera.MV_CC_EnumDevices_NET(MyCamera.MV_GIGE_DEVICE | MyCamera.MV_USB_DEVICE, ref list);if (ret != MyCamera.MV_OK) throw new COMException("Enum fail", ret);for (int i = 0; i < list.nDeviceNum; i++){var info = (MyCamera.MV_CC_DEVICE_INFO)Marshal.PtrToStructure(list.pDeviceInfo[i],typeof(MyCamera.MV_CC_DEVICE_INFO));string sn = GetSerial(info);if (sn.Equals(serial, StringComparison.OrdinalIgnoreCase)){_info = info;return;}}throw new COMException("Serial not found", -1);}public void Connect(){lock (_lock){if (_open) return;int ret = _cam.MV_CC_CreateDevice_NET(ref _info);if (ret != MyCamera.MV_OK) throw new COMException("Create fail", ret);ret = _cam.MV_CC_OpenDevice_NET();if (ret != MyCamera.MV_OK) throw new COMException("Open fail", ret);if (_info.nTLayerType == MyCamera.MV_GIGE_DEVICE){int pkt = _cam.MV_CC_GetOptimalPacketSize_NET();if (pkt > 0) _cam.MV_CC_SetIntValueEx_NET("GevSCPSPacketSize", pkt);}_open = true;}}public void Disconnect(){StopStream();lock (_lock){if (!_open) return;_cam.MV_CC_CloseDevice_NET();_cam.MV_CC_DestroyDevice_NET();_open = false;}}public string Shot(int exposure = 13000, float gain = 1.0f){lock (_lock){if (!_open) throw new COMException("Not connected", -1);SetExposureGain(exposure, gain);// 1. 连续模式 + 开始抓图_cam.MV_CC_SetEnumValue_NET("TriggerMode", 0);int ret = _cam.MV_CC_StartGrabbing_NET();if (ret != MyCamera.MV_OK) throw new COMException("StartGrabbing fail", ret);// 2. 取一帧var frame = new MyCamera.MV_FRAME_OUT();ret = _cam.MV_CC_GetImageBuffer_NET(ref frame, 5000);if (ret != MyCamera.MV_OK){_cam.MV_CC_StopGrabbing_NET();throw new COMException("Grab fail", ret);}string base64 = ToJpegBase64(ref frame);_cam.MV_CC_FreeImageBuffer_NET(ref frame);// 3. 停止抓图_cam.MV_CC_StopGrabbing_NET();return base64;}}public bool IsStreaming { get; private set; }public void StartStream(int exposure = 13000, float gain = 1f){lock (_lock){if (IsStreaming) return;if (!_open) throw new COMException("Not connected", -1);SetExposureGain(exposure, gain);_cam.MV_CC_SetEnumValue_NET("TriggerMode", 0);int ret = _cam.MV_CC_StartGrabbing_NET();if (ret != MyCamera.MV_OK) throw new COMException("Start grab fail", ret);IsStreaming = true;_cts = new CancellationTokenSource();_streamTask = Task.Run(StreamLoop, _cts.Token);}}public void StopStream(){lock (_lock){if (!IsStreaming) return;_cts.Cancel();_streamTask.Wait();_cam.MV_CC_StopGrabbing_NET();IsStreaming = false;}}/* 事件:每次出新图触发,COM 客户端可订阅 */[ComVisible(true)][Guid("EAA0C3F7-8D07-4EF1-B7A4-CE31F1A7DC2F")]public delegate void NewImageDelegate([MarshalAs(UnmanagedType.BStr)] string base64Jpeg);public event NewImageDelegate NewImage;private void StreamLoop(){var frame = new MyCamera.MV_FRAME_OUT();while (!_cts.Token.IsCancellationRequested){int ret = _cam.MV_CC_GetImageBuffer_NET(ref frame, 1000);if (ret == MyCamera.MV_OK){string b64 = ToJpegBase64(ref frame);_cam.MV_CC_FreeImageBuffer_NET(ref frame);NewImage?.Invoke(b64);}}}/* ---------- helper ---------- */private static string GetSerial(MyCamera.MV_CC_DEVICE_INFO info){if (info.nTLayerType == MyCamera.MV_GIGE_DEVICE){var gige = (MyCamera.MV_GIGE_DEVICE_INFO_EX)MyCamera.ByteToStruct(info.SpecialInfo.stGigEInfo, typeof(MyCamera.MV_GIGE_DEVICE_INFO_EX));return gige.chSerialNumber;}else{var usb = (MyCamera.MV_USB3_DEVICE_INFO_EX)MyCamera.ByteToStruct(info.SpecialInfo.stUsb3VInfo, typeof(MyCamera.MV_USB3_DEVICE_INFO_EX));return usb.chSerialNumber;}}private void SetExposureGain(int exp, float gain){_cam.MV_CC_SetEnumValue_NET("ExposureAuto", 0);_cam.MV_CC_SetFloatValue_NET("ExposureTime", exp);_cam.MV_CC_SetEnumValue_NET("GainAuto", 0);_cam.MV_CC_SetFloatValue_NET("Gain", gain);}// 默认拍照使用灰度模式, 兼容几乎所有相机private unsafe string ToJpegBase64(ref MyCamera.MV_FRAME_OUT frame){int w = frame.stFrameInfo.nWidth;int h = frame.stFrameInfo.nHeight;int nFrameBufLen = w * h; // 手动计算缓冲区大小using var bmp = new Bitmap(w, h, w, PixelFormat.Format8bppIndexed, (IntPtr)frame.pBufAddr);// 设置灰度调色板var pal = bmp.Palette;for (int i = 0; i < 256; i++)pal.Entries[i] = Color.FromArgb(i, i, i);bmp.Palette = pal;using var ms = new MemoryStream();bmp.Save(ms, ImageFormat.Jpeg);return Convert.ToBase64String(ms.ToArray());}}
}

注册:
管理员身份运行终端

regsvr32 "W:\Lab\exp42-hikvision-conn\Test\HikVision.comhost.dll"

测试代码(用法极简):

// Program.cs
// dotnet run 即可,会在工作目录生成 shot.jpg
// 需要项目文件 <Project Sdk="Microsoft.NET.Sdk"><PropertyGroup>
//   <OutputType>Exe</OutputType><TargetFramework>net8.0-windows</TargetFramework>
//   <PlatformTarget>x86</PlatformTarget><!-- 或 x64,与 COM 注册一致 -->
// </PropertyGroup></Project>using System;
using System.IO;
using System.Runtime.InteropServices;namespace ComHikDemo
{internal class Program{static void Main(){// 1. 创建 COM 对象Type t = Type.GetTypeFromProgID("HikVisionCom.HikCamera");if (t == null) throw new Exception("HikVisionCom.HikCamera 未注册");dynamic cam = Activator.CreateInstance(t);try{// 2. 初始化并连接(把下面串号换成你的相机序列号)string serial = "00DA4347368";cam.Init(serial);cam.Connect();// 3. 单帧采集,返回 Base64// string b64 = cam.Shot(13000, 1.0f);string b64 = cam.Shot();// 4. 解码保存byte[] jpeg = Convert.FromBase64String(b64);File.WriteAllBytes("shot.jpg", jpeg);Console.WriteLine("已保存 shot.jpg");}finally{// 5. 断开并释放cam.Disconnect();Marshal.ReleaseComObject(cam);}}}
}

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

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

相关文章

CF840C On the Bench 分析

题目概述 题目链接:https://www.luogu.com.cn/problem/CF840C。 给你 \(n\) 给数,将他们排列成一个序列并满足相邻两项 \(a_i,a_{i+1}\) 相乘不为平方数。问方案。 分析 我只说明一种解法,其他类的解法总结见:http…

HubSpot如何构建MCP服务器实现AI代理集成

HubSpot产品执行副总裁分享公司如何基于Model Context Protocol构建远程MCP服务器,详细解析技术架构选择、认证实现、与现有系统集成等核心挑战,以及AI代理在CRM领域的实际应用场景。HubSpot的MCP实现:CRM公司的AI代…

CSP-S 2025 趋势记

有个人 CSP-S 寄飞了,我不说是谁。感觉模拟赛也没啥动力打了。 T1 写了 \(10\) min 切了,非常自信。T2 写了 \(30\) min 被卡成 \(80\) 了,趋势。 然后开始传统艺能发呆,T3 看半天看错题了,看成可以替换无限次了,…

苹果手机iOS15.8.2 – 16.7.8最新越狱方法

支持设备 越狱支持所有 A9-A11 片上系统 (SoC)。您可以在下面找到兼容的 Palera1n 越狱 iPhone 和 iPad 的实际列表。越狱经过测试,可以在运行 iOS 15 的 iPhone X (GSM)、iPhone 8、iPhone 7 和 iPhone 6s上运行和工…

威联通NAS部署umami - 详解

pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …

后端八股之Redis - 详解

pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …

AGC052 VP 记录

场切 \(0\) 道题,被猜性质猜结论题气笑了. A 后来回想起来,这个题好像确实在北京集训讲过. 有 \(4\) 种合法的构造:\(0\overbrace{1\cdots1}^{n个} \overbrace{0\cdots0}^{n个}\),\(1\overbrace{0\cdots0}^{n个} \…

结合400行mini-react代码,图文解说React原理

引言: 在我学习React原理的时候,一上来看的非常全而细节的书/博客(头大),或者是看的教你实现一个简单mini-react(还是一知半解),最终学的痛苦又效果不好。所以,写了这篇博客,希望能帮助您入门React原理。此外…

UE:告别加载卡顿!一键合并StaticMeshActor方案

© mengzhishanghun 原创文章 首发于 博客园 禁止未经授权转载前言 大型UE场景打包后首次加载时,经常遇到长时间卡顿甚至假死现象。究其原因,成百上千个独立的StaticMeshActor在序列化、实例化时产生了巨大开销…

在Visual Studio使用Qt的插件机制进行开发 - 指南

在Visual Studio使用Qt的插件机制进行开发 - 指南pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas",…

摸鱼笔记[2]-提取windows已安装的驱动

使用`DriverStoreExplorer`提取windows已安装的海康相机.inf驱动文件.摘要 使用DriverStoreExplorer提取windows已安装的海康相机.inf驱动文件. 实现 [https://github.com/lostindark/DriverStoreExplorer] Driver Sto…

CF2013D 题解

提供一个二分做法。 因为当 \(a_i > a_{i + 1}\) 是做操作是不劣的,所以最终 \(a\) 一定单调不降。那么我们二分一个最小的 \(\max(a_i)\) 和最大的 \(\min(a_i)\),答案就是 \(\max(a_i) - \min(a_i)\)。 下面说一…

题解:AT_agc068_a [AGC068A] Circular Distance

牛牛题,看了很多次才看懂 题意:给出 \(L,n\),问在一个 \(L\) 长的环上,放置 \(n\) 个点,定义两点距离为两种路径中长度较短的长度,问所有放置方式的点的距离最大值之和。 做法: 首先先强制选定 \(0\) 号点,最后…

P14461 题解

消一消元: \[\begin{aligned}F_i&= G_{i - 1} + G_{i - 1} \\&= F_{i - 2} - F_{i - 2} + F_{i - 2} - F_{i - 2} \\&= F_{i - 2} - F_{i - 2} \end{aligned} \]类似的: \[G_i = G_{i - 2} - G_{i - 2} …

Nim 游戏与 SG 函数

已完成今日《Nim 游戏与 SG 函数》大学习。 本文比较基础,并未涉及到各种各样的 Nim 游戏,因为笔者比较菜。 1. 公平组合游戏 定义一个游戏为公平组合游戏,当且仅当:双方都知道当前局面的所有信息。 每一步的操作与…

题解:Luogu P11114 [ROI 2024] 小推车 (Day 1)

题意 有一排编号为 \(1\sim n\) 的座位。有 \(k\) 种饮料,第 \(i\) 名乘客想要喝第 \(a_i\) 种饮料。小推车需要从 \(0\) 位置出发,最终走到 \(n+1\) 位置,按顺序给每名乘客分饮料。推车上有 \(m\) 个瓶子,每个瓶子…

摸鱼笔记[1]-windows设置双网卡优先级(跃点数)

windows系统通过设置跃点数以设置双网卡优先级, 实现工控局域网网卡和互联网网卡各司其职, 电脑同时访问局域网和互联网.摘要 windows系统通过设置跃点数以设置双网卡优先级, 实现工控局域网网卡和互联网网卡各司其职,…