本文記錄一個隱藏極深的 BUG 完整排查過程:從現象復現、斷點定位、根因分析到最終修復,展示系統化除錯思維。
正常讀取均無崩潰。
修改 cvLoadImage 旗標為 -1(原始讀取,保持通道數不變),在「圖片文件」模式下讀取灰度圖進行性別識別 → 程序崩潰。
// 錯誤代碼
if (img->nChannels = 3) { // 永遠為真!
cvCvtColor(img, gray, CV_BGR2GRAY);
}
現象:灰度圖(單通道)被強制灰度化 → 崩潰。
教訓:== vs = 經典錯誤,彩色圖測試時不暴露,極具隱蔽性。
修復 BUG 1 後再次運行,崩潰於繪製矩形處,發現同樣的 if (img->nChannels = 3) 錯誤。
修復前兩個 BUG 後,程序在 cvReleaseImage(&gray) 處崩潰。調試發現:
faceImage = img 是淺拷貝(指針賦值),兩變量共享同一塊內存cvCvtColor(會隱式深拷貝 ROI 區域),直接淺拷貝faceImage 導致 img、gray 同步被釋放 → 後續釋放 gray 觸發雙重釋放崩潰faceImage 應存人臉 ROI 區域,實則存整圖 → 性別識別輸入錯誤// 問題代碼
cvSetImageROI(img, *rect); // 設置 ROI
IplImage* faceImage = cvCreateImage(cvSize(rect->width, rect->width), IPL_DEPTH_8U, 1);
if (img->nChannels == 3) {
cvCvtColor(img, faceImage, CV_BGR2GRAY); // 隱式複製 ROI 區域 → 深拷貝
} else {
faceImage = img; // 淺拷貝!ROI 無效,且共享內存
}
核心矛盾:cvCvtColor 會處理 ROI 並產生新圖像;直接賦值則忽略 ROI 且共享內存。
使用 cvCopy(支持 ROI 複製)替換賦值語句:
// 修復後
cvSetImageROI(img, *rect);
IplImage* faceImage = cvCreateImage(cvSize(rect->width, rect->width), IPL_DEPTH_8U, 1);
if (img->nChannels == 3) {
cvCvtColor(img, faceImage, CV_BGR2GRAY);
} else {
cvCopy(img, faceImage); // 深拷貝 ROI 區域
}
cvResetImageROI(img);
驗證:faceImage 正確保存分割後的人臉圖像,程序穩定運行。
IplImage 需手動 cvReleaseImage,淺拷貝極易導致雙重釋放下一篇將引入攝像頭視頻流實時識別。