基于C++与OpenCV生成轮廓直方图的技术求助(多目标跟踪与遮挡识别)
Hey there! Let's work through your contour histogram problem—since you've already nailed contour detection, we're just a few steps away from building those histograms for multi-object tracking and occlusion recovery. Here's a straightforward, actionable approach tailored to your use case:
First, you need to grab the actual region of the object from your original color frame (not the subtracted grayscale one—color features are way more useful for distinguishing objects). For irregular shapes, you can use either a bounding rectangle or a precise mask based on the contour.
Option 1: Bounding Rectangle ROI (Faster)
// Assume you have your contours, hierarchy, and original color frame "frame" std::vector<std::vector<cv::Point>> contours; std::vector<cv::Vec4i> hierarchy; cv::findContours(frameSubtracao_gray.clone(), contours, hierarchy, cv::RETR_EXTERNAL, cv::CHAIN_APPROX_SIMPLE); // Loop through each detected contour for (size_t i = 0; i < contours.size(); i++) { // Get the bounding rectangle of the contour cv::Rect roiRect = cv::boundingRect(contours[i]); // Extract the ROI from the original color frame cv::Mat objectRoi = frame(roiRect); // Convert ROI to HSV space (more stable for color histograms than BGR) cv::Mat hsvRoi; cv::cvtColor(objectRoi, hsvRoi, cv::COLOR_BGR2HSV); }
Option 2: Precise Masked ROI (For Irregular Shapes)
If you want to ignore pixels outside the exact contour (e.g., for highly irregular objects), use a mask:
cv::Mat mask = cv::Mat::zeros(frame.size(), CV_8UC1); // Draw and fill the contour on the mask cv::drawContours(mask, contours, i, cv::Scalar(255), cv::FILLED); // Extract the ROI using the mask cv::Mat objectRoi; frame.copyTo(objectRoi, mask); cv::Mat hsvRoi; cv::cvtColor(objectRoi, hsvRoi, cv::COLOR_BGR2HSV);
We'll use the H (hue) and S (saturation) channels of HSV—they're less sensitive to lighting changes than brightness (V). Here's how to compute and normalize the histogram:
// Define histogram parameters int hueBins = 50; int satBins = 60; int histSize[] = {hueBins, satBins}; // HSV ranges: Hue 0-179, Saturation 0-255 float hueRanges[] = {0, 180}; float satRanges[] = {0, 256}; const float* ranges[] = {hueRanges, satRanges}; // Channels to use: H (0) and S (1) int channels[] = {0, 1}; // Compute the histogram cv::Mat objectHist; cv::calcHist(&hsvRoi, 1, channels, cv::Mat(), objectHist, 2, histSize, ranges, true, false); // Normalize the histogram (makes comparison easier later) cv::normalize(objectHist, objectHist, 0, 1, cv::NORM_MINMAX, -1, cv::Mat());
To match new detected objects with your tracked targets, compare their histograms using a similarity metric. The Bhattacharyya distance works great here—lower values mean more similar histograms.
// Assume you have a stored histogram for a tracked target "targetHist" double similarity = cv::compareHist(objectHist, targetHist, cv::HISTCMP_BHATTACHARYYA); // Adjust the threshold based on your testing (e.g., <0.3 = match) if (similarity < 0.3) { // This new object matches your tracked target! }
- Never use the subtracted grayscale frame for histograms—it only has foreground/background info, no color details to distinguish objects. Always use the original color frame's ROI.
- For multi-target tracking, store each target's histogram alongside an ID and last known position (e.g., in a struct like
struct TrackedTarget { int id; cv::Mat hist; cv::Rect lastPos; };). - If occlusion happens, keep the target's histogram stored and re-match it when the object reappears.
内容的提问来源于stack exchange,提问作者Alex Colussi

