📄 learnedcolor.cpp
字号:
#include "Common.h"#include "LearnedColor.h"#include "Exceptions.h"//// Constructor//LearnedColor::LearnedColor() : m_truth_map(NULL), m_truth_pos(0), m_truth_neg(0), m_rgb_lookup_numbins(0), m_rgb_lookup_binsize(0){} // (Constructor)LearnedColor::~LearnedColor(){}void LearnedColor::Initialize(int width, int height){ m_truth_map = cvCreateImage(cvSize(width, height), IPL_DEPTH_32F, 1);}void LearnedColor::DrawOverlay(IplImage* rgbImage, int overlay_level, const CRect& roi){ if (overlay_level>=3) { Backproject(rgbImage, roi); }}/* draw the backprojection of the learned RGB lookup table */void LearnedColor::Backproject(IplImage* rgbImage, const CRect& roi){ ASSERT(rgbImage && rgbImage->imageData); ColorBGR black; black.red = black.green = black.blue = 0; int start_x = max(0, roi.left); int start_y = max(0, roi.top); int stop_x = min(rgbImage->width, roi.right); int stop_y = min(rgbImage->height, roi.bottom); for (int y=start_y; y<stop_y; y++) { ColorBGR* prgb = (ColorBGR*) rgbImage->imageData; prgb += y*rgbImage->width + start_x; for (int x=start_x; x<stop_x; x++, prgb++) { // if not foreground, set pixel to black prgb->red = prgb->green = prgb->blue = (BYTE) (255 * LookupProb(*prgb));// if (LookupProb(*prgb)<0.5) {// *prgb = black;// } } } int width = min(rgbImage->width-roi.left, min(roi.right, rgbImage->width-1)-roi.left); int height = min(rgbImage->height-roi.top, min(roi.bottom, rgbImage->height-1)-roi.top); CvRect cvBox = cvRect(roi.left, roi.top, width, height); cvSetImageROI(rgbImage, cvBox);// cvErode(rgbImage, rgbImage, NULL, 2); // cvDilate(rgbImage, rgbImage, NULL, 2); cvResetImageROI(rgbImage);}/* return (in "map") the probabilities based on the learned RGB lookup table* map must be allocated image with IPL_DEPTH_8U */void LearnedColor::CreateMap(const IplImage* rgbImage, IplImage* mapImage, const CRect& roi) const{ ASSERT(rgbImage && rgbImage->imageData); ASSERT(mapImage && mapImage->imageData); ASSERT(mapImage->width==rgbImage->width && mapImage->height==rgbImage->height); int start_x = max(0, roi.left); int start_y = max(0, roi.top); int stop_x = min(rgbImage->width, roi.right); int stop_y = min(rgbImage->height, roi.bottom); for (int y=start_y; y<stop_y; y++) { ColorBGR* prgb = (ColorBGR*) rgbImage->imageData; prgb += y*rgbImage->width + start_x; BYTE* pmap = (BYTE*) mapImage->imageData; pmap += y*mapImage->width + start_x; for (int x=start_x; x<stop_x; x++, prgb++, pmap++) { *pmap = (BYTE) (255*LookupProb(*prgb)); } }}#ifdef DEBUG// non-debug version is inlined in LearnedColor.hint LearnedColor::GetRGBLookupIndex(int x, int y, int z, int size, int arraylen) const{ ASSERT(x>=0 && y>=0 && z>=0); ASSERT(size); int index = z*size*size + y*size + x; ASSERT(0<=index && index<arraylen); return index;}#endif // DEBUG/* look up the probability for the given color sample * in the learned RGB table */double LearnedColor::LookupProb(ColorBGR sample) const{ ASSERT(m_rgb_lookup.size()); ASSERT(m_rgb_lookup_binsize); int bR = sample.red/m_rgb_lookup_binsize; int bG = sample.green/m_rgb_lookup_binsize; int bB = sample.blue/m_rgb_lookup_binsize; ASSERT(bR<m_rgb_lookup_numbins && bG<m_rgb_lookup_numbins && bB<m_rgb_lookup_numbins); double prob = m_rgb_lookup[GetRGBLookupIndex(bR, bG, bB, m_rgb_lookup_numbins, (int) m_rgb_lookup.size())]; return prob;}void LearnedColor::TestSegmentation(IplImage* rgbImage, const CRect& roi, double* fpr, double* dr, bool draw){ // let's look at each pixel(sample) ColorBGR black; black.red = black.green = black.blue = 0; int start_x = max(0, roi.left); int start_y = max(0, roi.top); int stop_x = min(rgbImage->width, roi.right); int stop_y = min(rgbImage->height, roi.bottom); int miss_pos=0, hit_pos=0, miss_neg=0, hit_neg=0; for (int y=start_y; y<stop_y; y++) { ColorBGR* prgb = (ColorBGR*) rgbImage->imageData; float* pprob = (float*) m_truth_map->imageData; prgb += y*rgbImage->width + start_x; pprob += y*rgbImage->width + start_x; for (int x=start_x; x<stop_x; x++, prgb++, pprob++) { // only consider pixels in the positive and negative areas if (*pprob!=1.0 && *pprob!=-1.0) { continue; } bool is_fore = (LookupProb(*prgb)>=0.5); // write to output buffer if (is_fore) { if (*pprob==1) { hit_pos++; } else { miss_neg++; } } else { if (*pprob==-1) { hit_neg++; } else { miss_pos++; } if (draw) *prgb = black; } } // end x } // end y *fpr = (double)miss_neg/(double)(miss_neg+hit_neg); *dr = (double)hit_pos/(double)(hit_pos+miss_pos); if (draw) { int height = 200; cvRectangle(rgbImage, cvPoint(0, 0), cvPoint(20, height), CV_RGB(255,0,0), 1); cvRectangle(rgbImage, cvPoint(25, 0), cvPoint(45, height), CV_RGB(0,255,0), 1); cvRectangle(rgbImage, cvPoint(0, 0), cvPoint(20, (int)(height* *fpr)), CV_RGB(255,0,0), CV_FILLED); cvRectangle(rgbImage, cvPoint(25, 0), cvPoint(45, (int)(height* *dr)), CV_RGB(0,255,0), CV_FILLED); }}void LearnedColor::SortSamplesIntoBins(vector<ColorBGR> samples, int* cube, int num_bins){ ASSERT(num_bins); int binsize = (int)(256.0/(double)num_bins); ASSERT(binsize); int num_samples = (int)samples.size(); for (int indx=0; indx<num_samples; indx++) { int bR = samples[indx].red/binsize; int bG = samples[indx].green/binsize; int bB = samples[indx].blue/binsize; ASSERT(bR<num_bins && bG<num_bins && bB<num_bins); int index = bB*num_bins*num_bins + bG*num_bins + bR; cube[index]++; }}#pragma warning (disable:4786)void LearnedColor::LearnFromGroundTruth(IplImage* rgbImage, const CuScanMatch& match, ConstMaskIt mask){ VERBOSE0(5, "HandVu: learning color from ground truth"); CRect bbox; SetGroundTruth(match, mask, bbox); LearnLookupCube(rgbImage, bbox);}#pragma warning (default:4786)void LearnedColor::LearnLookupCube(IplImage* rgbImage, const CRect& bbox){ // positive and negative areas should be set through SetTrainingAreas ASSERT(m_truth_pos>0 && m_truth_neg>0); // collect pixels; that's faster than running through the image // multiple times vector<ColorBGR> foreground; vector<ColorBGR> background; foreground.reserve(m_truth_pos); background.reserve(m_truth_neg);/* int start_x = 0; int start_y = 0; int stop_x = rgbImage->width; int stop_y = rgbImage->height; */ int start_x = max(0, bbox.left); int start_y = max(0, bbox.top); int stop_x = min(rgbImage->width, bbox.right); int stop_y = min(rgbImage->height, bbox.bottom); for (int y=start_y; y<stop_y; y++) { ColorBGR* prgb = (ColorBGR*) rgbImage->imageData; float* pprob = (float*) m_truth_map->imageData; prgb += y*rgbImage->width + start_x; pprob += y*rgbImage->width + start_x; for (int x=start_x; x<stop_x; x++, prgb++, pprob++) { // only consider pixels in the positive and negative areas if (*pprob==1.0) { foreground.push_back(*prgb); } else if (*pprob==-1.0) { background.push_back(*prgb); } } } ASSERT(m_truth_pos==(int)foreground.size()); ASSERT(m_truth_neg==(int)background.size()); // init the learning/counting m_rgb_lookup_numbins = 2; CFloatVector lookup_prev; m_rgb_lookup.resize(0); int* F_curr = NULL; int* B_curr = NULL; const int min_num_samples = 5; // stop breaking cells up if less // than min_num_samples samples are in cell // increase the number of bins per dimension until the number of samples per // bin does not exceed a threshold double max_r_xyz_curr; do { m_rgb_lookup_numbins *= 2; int cubed_size = m_rgb_lookup_numbins*m_rgb_lookup_numbins*m_rgb_lookup_numbins; m_rgb_lookup.swap(lookup_prev); m_rgb_lookup.resize(cubed_size); delete[] F_curr; F_curr = new int[cubed_size]; memset(F_curr, 0, cubed_size*sizeof(int)); delete[] B_curr; B_curr = new int[cubed_size]; memset(B_curr, 0, cubed_size*sizeof(int)); SortSamplesIntoBins(foreground, F_curr, m_rgb_lookup_numbins); SortSamplesIntoBins(background, B_curr, m_rgb_lookup_numbins); max_r_xyz_curr = 0; for (int z=0; z<m_rgb_lookup_numbins; z++) { for (int y=0; y<m_rgb_lookup_numbins; y++) { for (int x=0; x<m_rgb_lookup_numbins; x++) { // find the probability of pixels in this bin to be foreground color int index = GetRGBLookupIndex(x,y,z,m_rgb_lookup_numbins, (int) m_rgb_lookup.size()); int F = F_curr[index]; int B = B_curr[index]; int n_xyz_curr = F + B; if (n_xyz_curr<min_num_samples && (int)lookup_prev.size()>0) { m_rgb_lookup[index] = lookup_prev[GetRGBLookupIndex(x/2,y/2,z/2,m_rgb_lookup_numbins/2, (int) lookup_prev.size())]; } else { double rc = (double)n_xyz_curr/ (double)(m_truth_pos+m_truth_neg); max_r_xyz_curr = max(max_r_xyz_curr, rc); double f = (double)F/(double)m_truth_pos; double b = (double)B/(double)m_truth_neg; if (f!=0 && b!=0) { m_rgb_lookup[index] = (float) (f/(f+b)); } else if (f==0 && b!=0) { m_rgb_lookup[index] = 0.0f; } else if (f!=0 && b==0) { m_rgb_lookup[index] = 1.0f; } else if ((int)lookup_prev.size()>0) { m_rgb_lookup[index] = lookup_prev[GetRGBLookupIndex(x/2,y/2,z/2, m_rgb_lookup_numbins/2, (int) lookup_prev.size())]; } else { m_rgb_lookup[index] = 0.0f; } } ASSERT(0<=m_rgb_lookup[index]); ASSERT(m_rgb_lookup[index]<=1); } } } } while (max_r_xyz_curr>=0.05 && m_rgb_lookup_numbins<64); m_rgb_lookup_binsize = (int)(256.0/(double)m_rgb_lookup_numbins); delete[] F_curr; delete[] B_curr;}void LearnedColor::GetMostRightUpBlob(IplImage* rgbImage, const CRect& roi, CvPoint2D32f& pos){ int start_x = max(0, roi.left); int start_y = max(0, roi.top); int stop_x = min(rgbImage->width, roi.right); int stop_y = min(rgbImage->height, roi.bottom); int width = stop_x-start_x; int height = stop_y-start_y; ASSERT(rgbImage && rgbImage->imageData); int cnt_consecutive = 0; int diag = 1; do { ColorBGR* prgb = (ColorBGR*) rgbImage->imageData; prgb += start_y*rgbImage->width + stop_x-diag; for (int x=stop_x-diag, y=start_y; x<stop_x && y<stop_y; x++, y++) { if (LookupProb(*prgb)>=0.5) { cnt_consecutive ++; if (cnt_consecutive>20) { pos.x = (float)x; pos.y = (float)y; cvCircle(rgbImage, cvPoint(x, y), 12, CV_RGB(0, 255, 0), 1); return; } } else { cnt_consecutive = 0; } prgb += rgbImage->width + 1; } diag++; } while (diag<width+height); // no blob found pos.x = -1; pos.y = -1;}#pragma warning (disable:4786)void LearnedColor::SetGroundTruth(const CuScanMatch& match, ConstMaskIt mask, CRect& bbox){ cvSet(m_truth_map, cvScalar(0)); m_truth_pos = 0; m_truth_neg = 0; // set positive pixels where the mask has a skin-color // probability of at least scp_thresh (skin-color-prob) const double scp_thresh = 0.7; double scale_x = (double)(match.right-match.left-1)/((*mask).second.GetWidth()-1.); double scale_y = (double)(match.bottom-match.top-1)/((*mask).second.GetHeight()-1.); CvPixelPosition32f position; CV_INIT_PIXEL_POS(position, (float*)(m_truth_map->imageData), m_truth_map->widthStep, cvSize(m_truth_map->width, m_truth_map->height), 0, 0, m_truth_map->origin); ASSERT(m_truth_map->nChannels==1); for (int y=match.top; y<match.bottom; y++) { for (int x=match.left; x<match.right; x++) { int m_x = cvRound((double)(x-match.left)/scale_x); int m_y = cvRound((double)(y-match.top)/scale_y); double scp = (*mask).second.GetProb(m_x, m_y); if (scp>=scp_thresh) { CV_MOVE_TO(position, x, y, 1); *CV_GET_CURRENT(position, 1) = 1.0f; m_truth_pos ++; } } } // set negative area at a certain distance from the hand region int width = match.right-match.left; int height = match.bottom-match.top; int leftmost = match.left-width; int leftmid = match.left-width/2; int topmost = match.top-height; int topmid = match.top-height/2; int rightmost = match.right+width; int rightmid = match.right+width/2; int bottom = match.bottom; CRect neg_mask_left(leftmost, topmid, leftmid, bottom); ModifyGroundTruth(neg_mask_left, -1.0); CRect neg_mask_top(leftmost, topmost, rightmost, topmid); ModifyGroundTruth(neg_mask_top, -1.0); CRect neg_mask_right(rightmid, topmid, rightmost, bottom); ModifyGroundTruth(neg_mask_right, -1.0); bbox = CRect(leftmost, topmost, rightmost, bottom);}#pragma warning (default:4786)/* add areas with certain probabilities to the ground truth map with reset==true, the probability mask is zeroed out first, otherwise it's kept. probability==1 means foreground color for sure, probability==0 means background color; if probability==-1, that area is used to train a specific background color model. The area consists of four absolute coordinates (not width, height). all the computation will be done the next time Transform is called.*/void LearnedColor::ModifyGroundTruth(const CRect& area, double probability){ ASSERT(m_truth_map!=NULL); int x_to = min(area.right, m_truth_map->width); int x_from = max(0, area.left); int y_to = min(area.bottom, m_truth_map->height); CvPixelPosition32f position; CV_INIT_PIXEL_POS(position, (float*)(m_truth_map->imageData), m_truth_map->widthStep, cvSize(m_truth_map->width, m_truth_map->height), 0, 0, m_truth_map->origin); ASSERT(m_truth_map->nChannels==1); for (int y=max(0, area.top); y<y_to; y++) { CV_MOVE_TO(position, x_from, y, 1); for (int x=x_from; x<x_to; x++) { *CV_GET_CURRENT(position, 1) = (float) probability; CV_MOVE_RIGHT(position, 1); if (probability==1) { m_truth_pos ++; } else if (probability==-1) { m_truth_neg ++; } } }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -