使用海康機器人相機SDK實現基本參數配置(C語言示例)

在機器視覺項目開發中,相機的初始化、參數讀取與設置是最基礎也是最關鍵的環節。本文基于海康機器人(Hikrobot)提供的MVS SDK,使用C語言實現了一個簡潔的控制程序,完成設備枚舉、連接以及常用參數的獲取與設置。
📌 功能概述

該程序主要實現了以下功能:

初始化SDK環境
自動枚舉當前連接的所有相機設備(支持GigE、USB、CameraLink、CXP等類型)
打印每臺設備的基本信息,如型號、IP地址、用戶自定義名稱等
用戶可選擇指定設備進行操作
連接設備后,對常見類型的參數進行讀寫操作:整型參數:如圖像高度(Height)浮點型參數:如曝光時間(ExposureTime)枚舉型參數:如觸發模式(TriggerMode)布爾型參數:如圖像翻轉(ReverseX)字符串型參數:如設備用戶ID(DeviceUserID)
最后關閉設備并釋放資源
#include <stdio.h>           // 標準輸入輸出庫,用于 printf, scanf 等
#include <string.h>          // 字符串操作庫,用于 memset 等
#include "MvCameraControl.h" // 海康機器人(Hikrobot)相機 SDK 頭文件,包含所有相機控制函數和結構體定義// =================================================================================================
// 函數:PressEnterToExit
// 用途:等待用戶按回車鍵以退出程序(本程序中未實際調用,但可作為調試輔助)
// 說明:該函數用于阻塞程序,等待用戶輸入回車,常用于防止控制臺程序閃退
// =================================================================================================
void PressEnterToExit(void)
{int c;// 清空輸入緩沖區中的殘留字符(如之前 scanf 留下的換行符)while ( (c = getchar()) != '\n' && c != EOF );// 提示用戶按回車退出fprintf( stderr, "\n請按回車鍵退出。\n");// 再次等待用戶按回車while( getchar() != '\n');
}// =================================================================================================
// 函數:PrintDeviceInfo
// 用途:根據設備類型打印相機的詳細信息(型號、IP、用戶自定義名稱等)
// 參數:pstMVDevInfo - 指向設備信息結構體的指針
// 返回值:成功返回 true,失敗返回 false
// 說明:根據設備的傳輸層類型(GigE、USB、CameraLink 等)使用不同的結構體成員打印信息
// =================================================================================================
bool PrintDeviceInfo(MV_CC_DEVICE_INFO* pstMVDevInfo)
{// 檢查指針是否為空,防止空指針訪問if (NULL == pstMVDevInfo){printf("設備信息指針為空!\n");return false;}// 根據設備的傳輸層類型進行分支處理if (pstMVDevInfo->nTLayerType == MV_GIGE_DEVICE){// GigE 網口相機:解析當前IP地址(32位整數轉為點分十進制)int nIp1 = ((pstMVDevInfo->SpecialInfo.stGigEInfo.nCurrentIp & 0xff000000) >> 24);int nIp2 = ((pstMVDevInfo->SpecialInfo.stGigEInfo.nCurrentIp & 0x00ff0000) >> 16);int nIp3 = ((pstMVDevInfo->SpecialInfo.stGigEInfo.nCurrentIp & 0x0000ff00) >> 8);int nIp4 = (pstMVDevInfo->SpecialInfo.stGigEInfo.nCurrentIp & 0x000000ff);// 打印 GigE 相機信息printf("設備型號名稱: %s\n", pstMVDevInfo->SpecialInfo.stGigEInfo.chModelName);printf("當前IP地址: %d.%d.%d.%d\n" , nIp1, nIp2, nIp3, nIp4);printf("用戶自定義名稱: %s\n\n" , pstMVDevInfo->SpecialInfo.stGigEInfo.chUserDefinedName);}else if (pstMVDevInfo->nTLayerType == MV_USB_DEVICE){// USB3.0 相機:打印型號和用戶自定義名稱printf("設備型號名稱: %s\n", pstMVDevInfo->SpecialInfo.stUsb3VInfo.chModelName);printf("用戶自定義名稱: %s\n\n", pstMVDevInfo->SpecialInfo.stUsb3VInfo.chUserDefinedName);}else if (pstMVDevInfo->nTLayerType == MV_GENTL_GIGE_DEVICE){// GenTL 協議下的 GigE 相機:打印用戶自定義名、序列號、型號printf("用戶自定義名稱: %s\n", pstMVDevInfo->SpecialInfo.stGigEInfo.chUserDefinedName);printf("序列號: %s\n", pstMVDevInfo->SpecialInfo.stGigEInfo.chSerialNumber);printf("型號名稱: %s\n\n", pstMVDevInfo->SpecialInfo.stGigEInfo.chModelName);}else if (pstMVDevInfo->nTLayerType == MV_GENTL_CAMERALINK_DEVICE){// CameraLink 相機:打印用戶自定義名、序列號、型號printf("用戶自定義名稱: %s\n", pstMVDevInfo->SpecialInfo.stCMLInfo.chUserDefinedName);printf("序列號: %s\n", pstMVDevInfo->SpecialInfo.stCMLInfo.chSerialNumber);printf("型號名稱: %s\n\n", pstMVDevInfo->SpecialInfo.stCMLInfo.chModelName);}else if (pstMVDevInfo->nTLayerType == MV_GENTL_CXP_DEVICE){// CoaXPress (CXP) 相機:打印用戶自定義名、序列號、型號printf("用戶自定義名稱: %s\n", pstMVDevInfo->SpecialInfo.stCXPInfo.chUserDefinedName);printf("序列號: %s\n", pstMVDevInfo->SpecialInfo.stCXPInfo.chSerialNumber);printf("型號名稱: %s\n\n", pstMVDevInfo->SpecialInfo.stCXPInfo.chModelName);}else if (pstMVDevInfo->nTLayerType == MV_GENTL_XOF_DEVICE){// XoF (如光纖) 相機:打印用戶自定義名、序列號、型號printf("用戶自定義名稱: %s\n", pstMVDevInfo->SpecialInfo.stXoFInfo.chUserDefinedName);printf("序列號: %s\n", pstMVDevInfo->SpecialInfo.stXoFInfo.chSerialNumber);printf("型號名稱: %s\n\n", pstMVDevInfo->SpecialInfo.stXoFInfo.chModelName);}else{// 不支持的設備類型printf("設備類型不支持。\n");}return true;
}// =================================================================================================
// 主函數:main
// 用途:演示如何使用海康相機 SDK 進行設備枚舉、參數讀寫等基本操作
// 流程:
//  1. 初始化 SDK
//  2. 枚舉所有連接的相機設備
//  3. 打印設備信息
//  4. 用戶選擇一個設備
//  5. 創建句柄并打開設備
//  6. 讀取并設置各種類型的相機參數(int, float, enum, bool, string)
//  7. 關閉設備并銷毀句柄
//  8. 反初始化 SDK
// =================================================================================================
int main()
{int nRet = MV_OK;        // 用于存儲 SDK 函數調用的返回值,MV_OK 表示成功void* handle = NULL;     // 相機設備的句柄(類似于文件描述符),用于后續所有操作// 使用 do-while(0) 結構實現“偽 goto”,便于在任意步驟出錯時跳出并統一清理資源do {// ================== 步驟 1:初始化 SDK ==================nRet = MV_CC_Initialize();if (MV_OK != nRet){printf("初始化SDK失敗!錯誤碼 [0x%x]\n", nRet);break; // 初始化失敗,跳出循環}printf("SDK初始化成功。\n");// 定義設備列表結構體,用于存儲枚舉到的設備信息MV_CC_DEVICE_INFO_LIST stDeviceList;memset(&stDeviceList, 0, sizeof(MV_CC_DEVICE_INFO_LIST)); // 結構體清零,防止野值// ================== 步驟 2:枚舉設備 ==================// 枚舉所有支持的設備類型(GigE, USB, CameraLink, CXP, XoF)nRet = MV_CC_EnumDevices(MV_GIGE_DEVICE | MV_USB_DEVICE | MV_GENTL_CAMERALINK_DEVICE | MV_GENTL_CXP_DEVICE | MV_GENTL_XOF_DEVICE, &stDeviceList);if (MV_OK != nRet){printf("枚舉設備失敗!錯誤碼 [%x]\n", nRet);break;}// 檢查是否找到設備if (stDeviceList.nDeviceNum > 0){printf("共發現 %d 臺設備:\n", stDeviceList.nDeviceNum);for (int i = 0; i < stDeviceList.nDeviceNum; i++){printf("[設備 %d]:\n", i);MV_CC_DEVICE_INFO* pDeviceInfo = stDeviceList.pDeviceInfo[i]; // 獲取第 i 個設備的信息指針if (NULL == pDeviceInfo){break;} PrintDeviceInfo(pDeviceInfo); // 調用函數打印設備信息            }  } else{printf("未發現任何設備!\n");break; // 無設備,跳出}// ================== 步驟 3:用戶選擇設備 ==================printf("請輸入要操作的相機序號: ");unsigned int nIndex = 0;if(0 == scanf("%d", &nIndex)) // 檢查輸入是否為有效整數{printf("輸入格式錯誤!\n");break;}// 檢查用戶輸入的索引是否有效if (nIndex >= stDeviceList.nDeviceNum){printf("輸入錯誤!序號超出范圍。\n");break;}// ================== 步驟 4:創建設備句柄 ==================// 根據用戶選擇的設備信息創建句柄nRet = MV_CC_CreateHandle(&handle, stDeviceList.pDeviceInfo[nIndex]);if (MV_OK != nRet){printf("創建設備句柄失敗!錯誤碼 [%x]\n", nRet);break;}printf("設備句柄創建成功。\n");// ================== 步驟 5:打開設備 ==================// 打開指定的相機設備,建立通信nRet = MV_CC_OpenDevice(handle);if (MV_OK != nRet){printf("打開設備失敗!錯誤碼 [%x]\n", nRet);break;}printf("設備打開成功。\n");// ================== 步驟 6:獲取并設置各種類型的相機參數 ==================// --- 6.1 獲取 int 型參數:圖像高度 (Height) ---MVCC_INTVALUE stHeight = {0}; // 定義結構體存儲 int 型參數信息nRet = MV_CC_GetIntValue(handle, "Height", &stHeight);if (MV_OK == nRet){printf("圖像高度 - 當前值: %d\n", stHeight.nCurValue);printf("圖像高度 - 最大值: %d\n", stHeight.nMax);printf("圖像高度 - 最小值: %d\n", stHeight.nMin);printf("圖像高度 - 增量: %d\n\n", stHeight.nInc);}else{printf("獲取圖像高度失敗!錯誤碼 [%x]\n\n", nRet);}// --- 6.2 設置 int 型參數:圖像高度 ---unsigned int nHeightValue = 0;printf("請輸入要設置的圖像高度: ");if(0 == scanf("%d", &nHeightValue)){printf("輸入格式錯誤!\n");break;}// 注意:某些相機的寬高設置有步進要求(如16的倍數)nRet = MV_CC_SetIntValueEx(handle, "Height", nHeightValue);    if (MV_OK == nRet){printf("設置圖像高度成功!\n\n");}else{printf("設置圖像高度失敗!錯誤碼 [%x]\n\n", nRet);}// --- 6.3 獲取 float 型參數:曝光時間 (ExposureTime) ---MVCC_FLOATVALUE stExposureTime = {0};nRet = MV_CC_GetFloatValue(handle, "ExposureTime", &stExposureTime);if (MV_OK == nRet){printf("曝光時間 - 當前值: %f\n", stExposureTime.fCurValue);printf("曝光時間 - 最大值: %f\n", stExposureTime.fMax);printf("曝光時間 - 最小值: %f\n\n", stExposureTime.fMin);}else{printf("獲取曝光時間失敗!錯誤碼 [%x]\n\n", nRet);}// --- 6.4 設置 float 型參數:曝光時間 ---float fExposureTime = 0.0f;printf("請輸入要設置的曝光時間: ");if(0 == scanf("%f", &fExposureTime)){printf("輸入格式錯誤!\n");break;}nRet = MV_CC_SetFloatValue(handle, "ExposureTime", fExposureTime);if (MV_OK == nRet){printf("設置曝光時間成功!\n\n");}else{printf("設置曝光時間失敗!錯誤碼 [%x]\n\n", nRet);}// --- 6.5 獲取 enum 型參數:觸發模式 (TriggerMode) ---MVCC_ENUMVALUE stTriggerMode = {0};nRet = MV_CC_GetEnumValue(handle, "TriggerMode", &stTriggerMode);if (MV_OK == nRet){printf("觸發模式 - 當前值: %d\n", stTriggerMode.nCurValue);printf("支持的觸發模式數量: %d\n", stTriggerMode.nSupportedNum);for (unsigned int i = 0; i < stTriggerMode.nSupportedNum; ++i){printf("支持的觸發模式 [%d]: %d\n", i, stTriggerMode.nSupportValue[i]);}printf("\n");}else{printf("獲取觸發模式失敗!錯誤碼 [%x]\n\n", nRet);}// --- 6.6 設置 enum 型參數:觸發模式 ---unsigned int nTriggerMode = 0;printf("請輸入要設置的觸發模式: ");if(0 == scanf("%d", &nTriggerMode)){printf("輸入格式錯誤!\n");break;}nRet = MV_CC_SetEnumValue(handle, "TriggerMode", nTriggerMode);if (MV_OK == nRet){printf("設置觸發模式成功!\n\n");}else{printf("設置觸發模式失敗!錯誤碼 [%x]\n\n", nRet);}// --- 6.7 獲取 bool 型參數:圖像X方向翻轉 (ReverseX) ---bool bGetBoolValue = false;nRet = MV_CC_GetBoolValue(handle, "ReverseX", &bGetBoolValue);if (MV_OK == nRet){printf("圖像X方向翻轉 - 當前值: %s\n\n", bGetBoolValue ? "開啟" : "關閉");}else{printf("獲取圖像X方向翻轉狀態失敗!錯誤碼 = [%x]\n\n", nRet);}// --- 6.8 設置 bool 型參數:圖像X方向翻轉 ---int nSetBoolValue;bool bSetBoolValue;printf("請輸入圖像X方向翻轉狀態 (0=關閉, 1=開啟): ");if(0 == scanf("%d", &nSetBoolValue)){printf("輸入格式錯誤!\n");break;}bSetBoolValue = (nSetBoolValue != 0); // 將整數轉換為 boolnRet = MV_CC_SetBoolValue(handle, "ReverseX", bSetBoolValue);if (MV_OK == nRet){printf("設置圖像X方向翻轉成功!\n\n");}else{printf("設置圖像X方向翻轉失敗!錯誤碼 = [%x]\n\n", nRet);}// --- 6.9 獲取 string 型參數:設備用戶ID (DeviceUserID) ---MVCC_STRINGVALUE stStringValue = {0};nRet = MV_CC_GetStringValue(handle, "DeviceUserID", &stStringValue);if (MV_OK == nRet){printf("當前設備用戶ID: [%s]\n\n", stStringValue.chCurValue);}else{printf("獲取設備用戶ID失敗!錯誤碼 = [%x]\n\n", nRet);}// --- 6.10 設置 string 型參數:設備用戶ID ---unsigned char strValue[256]; // 用于存儲用戶輸入的字符串printf("請輸入要設置的設備用戶ID (字符串): ");if(0 == scanf("%s", strValue)) // 注意:此處有緩沖區溢出風險,實際應用中應使用 scanf_s 或 fgets{printf("輸入格式錯誤!\n");break;}nRet = MV_CC_SetStringValue(handle, "DeviceUserID", (char*)strValue);if (MV_OK == nRet){printf("設置設備用戶ID成功!\n\n");}else{printf("設置設備用戶ID失敗!錯誤碼 = [%x]\n\n", nRet);}// ================== 步驟 7:關閉設備 ==================nRet = MV_CC_CloseDevice(handle);if (MV_OK != nRet){printf("關閉設備失敗!錯誤碼 [%x]\n", nRet);break;}printf("設備已關閉。\n");// ================== 步驟 8:銷毀句柄 ==================nRet = MV_CC_DestroyHandle(handle);if (MV_OK != nRet){printf("銷毀設備句柄失敗!錯誤碼 [%x]\n", nRet);break;}handle = NULL; // 避免懸空指針printf("設備句柄已銷毀。\n");} while (0); // do-while(0) 結束,用于錯誤處理跳轉// ================== 步驟 9:異常清理 ==================// 如果循環中出錯導致 handle 不為 NULL,則在此處進行清理if (handle != NULL){MV_CC_DestroyHandle(handle);handle = NULL;}// ================== 步驟 10:反初始化 SDK ==================// 釋放 SDK 占用的全局資源MV_CC_Finalize();printf("SDK反初始化完成。\n");printf("程序退出。\n");return 0; // 程序正常退出
}

makefile為:

Demo: SetParam.cppg++ -g -o SetParam SetParam.cpp -I../../../../../include -Wl,-rpath=$(MVCAM_COMMON_RUNENV)/64 -L$(MVCAM_COMMON_RUNENV)/64 -lMvCameraControlclean:rm SetParam -rf
SDK初始化成功。
共發現 2 臺設備:
[設備 0]:
設備型號名稱: MV-CE120-10GM
當前IP地址: 169.254.183.31
用戶自定義名稱: [設備 1]:
設備型號名稱: MV-CE120-10GM
當前IP地址: 169.254.183.31
用戶自定義名稱: 請輸入要操作的相機序號: 0
設備句柄創建成功。
設備打開成功。
圖像高度 - 當前值: 3036
圖像高度 - 最大值: 3036
圖像高度 - 最小值: 32
圖像高度 - 增量: 2請輸入要設置的圖像高度: 3036
設置圖像高度成功!曝光時間 - 當前值: 5000.000000
曝光時間 - 最大值: 1999733.000000
曝光時間 - 最小值: 34.000000請輸入要設置的曝光時間: 4000
設置曝光時間成功!觸發模式 - 當前值: 0
支持的觸發模式數量: 2
支持的觸發模式 [0]: 0
支持的觸發模式 [1]: 1請輸入要設置的觸發模式: 1
設置觸發模式成功!圖像X方向翻轉 - 當前值: 關閉請輸入圖像X方向翻轉狀態 (0=關閉, 1=開啟): 1
設置圖像X方向翻轉成功!當前設備用戶ID: []請輸入要設置的設備用戶ID (字符串): 111
設置設備用戶ID成功!設備已關閉。
設備句柄已銷毀。
SDK反初始化完成。
程序退出。

? 適用場景

本示例適用于以下場景:

工業相機二次開發入門學習
快速驗證相機通信與參數配置
搭建相機控制模塊的基礎框架

🔧 使用說明

安裝最新版 Hikrobot MVS SDK
將 MvCameraControl.h 和相關庫文件加入工程
編譯并運行程序
根據提示選擇設備并設置參數

📝 結語

通過簡潔明了的C語言代碼,我們實現了對海康相機的核心控制功能。程序結構清晰,便于擴展為圖像采集、多相機管理等功能模塊。對于剛接觸視覺開發的工程師來說,是一個不錯的起點。

代碼已將所有輸出信息本地化為中文,提升調試體驗,便于團隊協作與現場部署。

完整源碼已附在文中,可直接編譯使用。

歡迎交流與優化!

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/diannao/98486.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/98486.shtml
英文地址,請注明出處:http://en.pswp.cn/diannao/98486.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

【IoTDB】時序數據庫選型指南:為何IoTDB成為工業大數據場景的首選?

【作者主頁】Francek Chen 【專欄介紹】???大數據與數據庫應用??? 大數據是規模龐大、類型多樣且增長迅速的數據集合&#xff0c;需特殊技術處理分析以挖掘價值。數據庫作為數據管理的關鍵工具&#xff0c;具備高效存儲、精準查詢與安全維護能力。二者緊密結合&#xff0…

用計算思維“破解”復雜Excel考勤表的自動化之旅

在我們日常工作中&#xff0c;經常會遇到一些看似簡單卻極其繁瑣的任務。手動處理一份結構復雜的Excel考勤表&#xff0c;就是典型的例子。它充滿了合并單元格、不規則的布局和隱藏的格式陷阱。面對這樣的挑戰&#xff0c;我們是選擇“卷起袖子&#xff0c;日復一日地手動復制粘…

PAT 1006 Sign In and Sign Out

1006 Sign In and Sign Out分數 25作者 CHEN, Yue單位 浙江大學At the beginning of every day, the first person who signs in the computer room will unlock the door, and the last one who signs out will lock the door. Given the records of signing ins and outs, yo…

【git】首次clone的使用采用-b指定了分支,還使用了--depth=1 后續在這個基礎上拉取所有的分支代碼方法

要解決當前問題&#xff08;從淺克隆轉換為完整克隆并獲取所有分支&#xff09;&#xff0c;請按照以下步驟操作&#xff1a; 步驟 1&#xff1a;檢查當前遠程地址 首先確認遠程倉庫地址是否正確&#xff1a; git remote -v步驟 2&#xff1a;修改遠程配置以獲取所有分支 默認淺…

蘿卜切丁機 機構筆記

蘿卜切丁機_STEP_模型圖紙免費下載 – 懶石網 機械工程師設計手冊 1是傳送帶 2是曲柄滑塊機構&#xff1f; 擠壓動作

多張圖片生成視頻模型技術深度解析

多張圖片生成視頻模型測試相比純文本輸入&#xff0c;有視覺參考約束的生成通常質量更穩定&#xff0c;細節更豐富 1. 技術原理和工作機制 多張圖片生成視頻模型是一種先進的AI技術&#xff0c;能夠接收多張輸入圖像&#xff0c;理解場景變化關系&#xff0c;并合成具有時間連…

中電金信:AI重構測試體系·智能化時代的軟件工程新范式

AI技術的迅猛發展正加速推動軟件工程3.0時代的到來&#xff0c;深刻地重塑了測試行業的運作邏輯&#xff0c;推動測試角色從“后置保障”轉變為“核心驅動力”。在大模型技術的助力下&#xff0c;測試質量和效能將顯著提升。9月5日至6日&#xff0c;Gtest2025全球軟件測試技術峰…

100、23種設計模式之適配器模式(9/23)

適配器模式&#xff08;Adapter Pattern&#xff09; 是一種結構型設計模式&#xff0c;它允許將不兼容的接口轉換為客戶端期望的接口&#xff0c;使原本由于接口不兼容而不能一起工作的類可以協同工作。 一、核心思想 將一個類的接口轉換成客戶期望的另一個接口使原本因接口不…

線上環境CPU使用率飆升,如何排查

線上環境CPU使用率飆升&#xff0c;如何排查 1.CPU飆升的常見原因 1. 代碼層面問題 死循環&#xff1a;錯誤的循環條件導致無限循環遞歸過深&#xff1a;沒有正確的終止條件算法效率低&#xff1a;O(n)或更高時間復雜度的算法處理大數據集頻繁GC&#xff1a;內存泄漏導致頻繁垃…

《sklearn機器學習——特征提取》

在 sklearn.feature_extraction 模塊中&#xff0c;DictVectorizer 是從字典&#xff08;dict&#xff09;中加載和提取特征的核心工具。它主要用于將包含特征名稱和值的 Python 字典列表轉換為機器學習算法所需的數值型數組或稀疏矩陣。 這種方法在處理結構化數據&#xff08;…

IEEE出版,限時早鳥優惠!|2025年智能制造、機器人與自動化國際學術會議 (IMRA 2025)

2025年智能制造、機器人與自動化國際學術會議 (IMRA2025)2025 International Conference on Intelligent Manufacturing, Robotics, and Automation中國?湛江2025年11月14日-2025年11月16日IMRA2025權威出版大咖云集穩定檢索智能制造、人工智能、機器人、物聯網&#xff08;Io…

C# 基于halcon的視覺工作流-章30-圓圓距離測量

C# 基于halcon的視覺工作流-章30-圓圓距離測量 本章目標&#xff1a; 一、利用圓卡尺找兩圓心&#xff1b; 二、distance_pp算子計算兩圓點距離&#xff1b; 三、匹配批量計算&#xff1b;本章是在章23-圓查找的基礎上進行測量使用&#xff0c;圓查找知識請閱讀章23&#xff0c…

java設計模式二、工廠

概述 工廠方法模式是一種常用的創建型設計模式&#xff0c;它通過將對象的創建過程封裝在工廠類中&#xff0c;實現了創建與使用的分離。這種模式不僅提高了代碼的復用性&#xff0c;還增強了系統的靈活性和可擴展性。本文將詳細介紹工廠方法模式的三種形式&#xff1a;簡單工廠…

Ubuntu 24.04 中 nvm 安裝 Node 權限問題解決

個人博客地址&#xff1a;Ubuntu 24.04 中 nvm 安裝 Node 權限問題解決 | 一張假鈔的真實世界 參考nvm的一個issue&#xff1a;https://github.com/nvm-sh/nvm/issues/3363 異常信息如下&#xff1a; $ nvm install 22 Downloading and installing node v22.19.0... Download…

Java面試-線程安全篇

一、synchronized關鍵字&#xff1a; 基本使用與作用&#xff1a;通過搶票代碼示例&#xff0c;展示了synchronized作為對象鎖&#xff0c;可避免多線程超賣或搶到同一張票問題&#xff0c;保證代碼原子性&#xff0c;同一時刻只有一個線程獲得鎖&#xff0c;其他線程阻塞。底層…

R 語言科研繪圖 --- 其他繪圖-匯總2

在發表科研論文的過程中&#xff0c;科研繪圖是必不可少的&#xff0c;一張好看的圖形會是文章很大的加分項。 為了便于使用&#xff0c;本系列文章介紹的所有繪圖都已收錄到了 sciRplot 項目中&#xff0c;獲取方式&#xff1a; R 語言科研繪圖模板 --- sciRplothttps://mp.…

【數學建模學習筆記】啟發式算法:粒子群算法

零基礎小白看懂粒子群優化算法&#xff08;PSO&#xff09;一、什么是粒子群優化算法&#xff1f;簡單說&#xff0c;粒子群優化算法&#xff08;PSO&#xff09;是一種模擬鳥群 / 魚群覓食的智能算法。想象一群鳥在找食物&#xff1a;每只鳥&#xff08;叫 “粒子”&#xff0…

【Gitlab】Ubuntu 20.04服務器部署Gitlab

寫一個 適用于 Ubuntu 20.04/22.04 的 GitLab 一鍵部署腳本&#xff0c;包括&#xff1a;安裝依賴安裝 GitLab CE配置公網 IP 或域名自動開啟 HTTPS&#xff08;Let’s Encrypt&#xff09;配置防火墻下面是完整腳本&#xff1a;#!/bin/bash# # GitLab 一鍵安裝腳本 # # 1. 檢…

Android 15重磅升級:16KB內存頁機制詳解與適配指南

一、背景隨著Android硬件架構的持續演進&#xff0c;新一代設備開始采用16KB內存頁&#xff08;Page Size&#xff09;機制&#xff0c;逐步替代傳統的4KB內存頁設計。此項底層變更對應用兼容性產生直接影響&#xff0c;特別是對依賴Native層庫、JNI接口或自定義內存管理模塊的…

Mybatis-8 動態SQL

動態SQL-官方文檔 文檔地址 動態 SQL_MyBatis中文網 為什么需要動態SQL 1、動態SQL是MyBatis的強大特性之一 2、使用JDBC或其它類似的框架&#xff0c;根據不同條件拼接SQL語句非常麻煩&#xff0c;例如拼接時要確保不能忘記添加必要的空格&#xff0c;還要注意去掉列表最后一…