void ProcessFrame(uint8 *pInputImg) { int c, r; int nc = OSC_CAM_MAX_IMAGE_WIDTH / 2; int siz = sizeof(data.u8TempImage[GRAYSCALE]); int Shift = 7; short Beta = 2;//the meaning is that in floating point the value of Beta is = 6/(1 << Shift) = 6/128 = 0.0469 uint8 MaxForeground = 120;//the maximum foreground counter value (at 15 fps this corresponds to less than 10s) struct OSC_PICTURE Pic1, Pic2;//we require these structures to use Oscar functions struct OSC_VIS_REGIONS ImgRegions;//these contain the foreground objects if (data.ipc.state.nStepCounter == 1) { /* this is the first time we call this function */ /* first time we call this; index 1 always has the background image */ memcpy(data.u8TempImage[BACKGROUND], data.u8TempImage[GRAYSCALE], sizeof(data.u8TempImage[GRAYSCALE])); /* set foreground counter to zero */ memset(data.u8TempImage[FGRCOUNTER], 0, sizeof(data.u8TempImage[FGRCOUNTER])); } else { /* this is the default case */ uint32 Hist[256]; uint8* p = &data.u8TempImage[GRAYSCALE][0]; memset(Hist, 0, sizeof(Hist)); uint32 w0 = 0; uint32 w1 = 0; uint32 m0 = 0; uint32 m1 = 0; float roh2 = 0; float roh2_actual = 0; uint8 k_best = 0; int i1,k,g; // a) loop over image for (i1=0;i1<siz;i1++) Hist[p[i1]] += 1; // b) find best k for (k = 0; k <= 255; k++) // main loop over K { for (g=0, w0=0, m0=0; g<=k; g++) { // loop from 0 to K w0 += Hist[g]; m0 += Hist[g] * g; } for (g=k+1, w1=0, m1=0; g<=255; g++) { // loop from K+1 to 255 w1 += Hist[g]; m1 += Hist[g] * g; } roh2_actual = ((float)w0*w1) * ( (((float)m0/w0) - ((float)m1/w1)) * (((float)m0/w0) - ((float)m1/w1)) ); if (roh2_actual > roh2) // evaluate maximum value of roh for best K { roh2 = roh2_actual; k_best = k; } } // write actual value of 'K' to index.xhtml data.ipc.state.actualK = k_best; /* apply threshold value 'k' to threshold image */ for (r = 0; r < siz; r += nc)/* we strongly rely on the fact that them images have the same size */ { for (c = 0; c < nc; c++) { /* determine the foreground estimate */ data.u8TempImage[THRESHOLD][r + c] = data.u8TempImage[GRAYSCALE][r + c] > k_best ? 0 : 0xff; } } /* { //for debugging purposes we log the background values to console out //we chose the center pixel of the image (adaption to other pixel is straight forward) int offs = nc*(OSC_CAM_MAX_IMAGE_HEIGHT/2)/2+nc/2; OscLog(INFO, "%d %d %d %d %d\n", (int) data.u8TempImage[GRAYSCALE][offs], (int) data.u8TempImage[BACKGROUND][offs], (int) data.u8TempImage[BACKGROUND][offs]-data.ipc.state.nThreshold, (int) data.u8TempImage[BACKGROUND][offs]+data.ipc.state.nThreshold, (int) data.u8TempImage[FGRCOUNTER][offs]); } */ for (r = nc; r < siz - nc; r += nc)/* we skip the first and last line */ { for (c = 1; c < nc - 1; c++)/* we skip the first and last column */ { unsigned char* p = &data.u8TempImage[THRESHOLD][r + c]; data.u8TempImage[EROSION][r + c] = *(p - nc - 1) & *(p - nc) & *(p - nc + 1) & *(p - 1) & *p & *(p + 1) & *(p + nc - 1) & *(p + nc) & *(p + nc + 1); } } for (r = nc; r < siz - nc; r += nc)/* we skip the first and last line */ { for (c = 1; c < nc - 1; c++)/* we skip the first and last column */ { unsigned char* p = &data.u8TempImage[EROSION][r + c]; data.u8TempImage[DILATION][r + c] = *(p - nc - 1) | *(p - nc) | *(p - nc + 1) | *(p - 1) | *p | *(p + 1) | *(p + nc - 1) | *(p + nc) | *(p + nc + 1); } } //wrap image DILATION in picture struct Pic1.data = data.u8TempImage[DILATION]; Pic1.width = nc; Pic1.height = OSC_CAM_MAX_IMAGE_HEIGHT / 2; Pic1.type = OSC_PICTURE_GREYSCALE; //as well as EROSION (will be used as output) Pic2.data = data.u8TempImage[EROSION]; Pic2.width = nc; Pic2.height = OSC_CAM_MAX_IMAGE_HEIGHT / 2; Pic2.type = OSC_PICTURE_BINARY;//probably has no consequences //have to convert to OSC_PICTURE_BINARY which has values 0x01 (and not 0xff) OscVisGrey2BW(&Pic1, &Pic2, 0x80, false); //now do region labeling and feature extraction OscVisLabelBinary(&Pic2, &ImgRegions); OscVisGetRegionProperties(&ImgRegions); //OscLog(INFO, "number of objects %d\n", ImgRegions.noOfObjects); //plot bounding boxes both in gray and dilation image Pic2.data = data.u8TempImage[GRAYSCALE]; OscVisDrawBoundingBoxBW(&Pic2, &ImgRegions, 255); OscVisDrawBoundingBoxBW(&Pic1, &ImgRegions, 128); } }
static void region_labeling(uint8_t* dst) { uint8_t tmp_buf[SZ]; /* input picture info */ struct OSC_PICTURE picin = { .data = IMAGE(DILATION), .width = NC, .height = OSC_CAM_MAX_IMAGE_HEIGHT / 2u, .type = OSC_PICTURE_GREYSCALE }; /* temporary binary image */ struct OSC_PICTURE picout = { .data = tmp_buf, .width = NC, .height = OSC_CAM_MAX_IMAGE_HEIGHT / 2u, .type = OSC_PICTURE_BINARY }; /* region labeling info */ struct OSC_VIS_REGIONS region_info; /* make a binary image */ OscVisGrey2BW(&picin, &picout, 0x80, false); /* now do the region labeling */ OscVisLabelBinary(&picout, ®ion_info); /* feature extraction */ OscVisGetRegionProperties(®ion_info); /* now copy the grayscale image to the labeling image */ memcpy(dst, IMAGE(GRAYSCALE), SZ); /* abuse the picin picture info to draw the bounding boxes */ picin.data = dst; draw_bbox(&picin, ®ion_info, 0x80); /* set the number of objects in the web gui */ data.ipc.state.objectcount = region_info.noOfObjects; } static uint8_t otsu(const uint8_t* img) { uint8_t ret; uint32_t histogram[256]; uint32_t k, g; uint32_t w0, w1; uint32_t mu0s, mu1s; float mu0, mu1; float sigma_b, sigma_max; /* initialise the histogram with zero */ memset(histogram, 0, sizeof(histogram)); /* calculate the histogram */ imhist(histogram, img); sigma_max = 0.0f; for(k = 0; k < 256; k++) { w0 = w1 = 0; mu0s = mu1s = 0; for(g = 0; g < 256; g++) { if(g <= k) { w0 += histogram[g]; mu0s += histogram[g] * g; } else { w1 += histogram[g]; mu1s += histogram[g] * g; } } mu0 = ((float)mu0s / (float)w0); mu1 = ((float)mu1s / (float)w1); sigma_b = ((float)(w0 * w1)) * (mu0 - mu1) * (mu0 - mu1); if(sigma_b > sigma_max) { sigma_max = sigma_b; ret = (uint8_t)k; } } return ret; }
void ProcessFrame(uint8 *pInputImg) { int c, r; int nc = OSC_CAM_MAX_IMAGE_WIDTH/2; int siz = sizeof(data.u8TempImage[GRAYSCALE]); short thresh; struct OSC_PICTURE Pic1, Pic2;//we require these structures to use Oscar functions struct OSC_VIS_REGIONS ImgRegions;//these contain the foreground objects if(data.ipc.state.nThreshold==0){ uint32 hist[256]; uint32 histMean[256]; uint32 Wtot,Mtot; uint8* p=data.u8TempImage[GRAYSCALE]; memset(hist,0,sizeof(hist)); for(int i=0;i<siz;i++){ hist[p[i]]++; } Wtot=siz; Mtot=0; memset(histMean,0,sizeof(hist)); for(int i=0;i<256;i++){ histMean[i]=hist[i]*i; Mtot+=histMean[i]; } float sigmaMax=0,t; int32 W0,W1,M0,M1,k,Wsum,Msum; Wsum=Msum=0; for(k=0;k<256;k++){ W0=W1=M0=M1=0; Wsum+=hist[k]; W0=Wsum; Msum+=histMean[k]; M0=Msum; W1=Wtot-W0; M1=Mtot-M0; M0=(int32)((float)M0/(float)W0); M1=(int32)((float)M1/(float)W1); M0=M0-M1; t=((float)M0)*((float)M0)*((float)W0)*((float)W1); if(t>sigmaMax){ thresh=k; sigmaMax=t; } } }else{ thresh=data.ipc.state.nThreshold*255/100; } /* this is the default case */ for(r = 0; r < siz; r+= nc)/* we strongly rely on the fact that them images have the same size */ { for(c = 0; c < nc; c++) { /* first determine the foreground estimate */ data.u8TempImage[THRESHOLD][r+c]=abs((short)data.u8TempImage[GRAYSCALE][r+c])>thresh ? 0:255; } } for(r = nc; r < siz-nc; r+= nc)/* we skip the first and last line */ { for(c = 1; c < nc-1; c++)/* we skip the first and last column */ { unsigned char* p = &data.u8TempImage[THRESHOLD][r+c]; data.u8TempImage[DILATION][r+c] = *(p-nc-1) | *(p-nc) | *(p-nc+1) | *(p-1) | *p | *(p+1) | *(p+nc-1) | *(p+nc) | *(p+nc+1); } } for(r = nc; r < siz-nc; r+= nc)/* we skip the first and last line */ { for(c = 1; c < nc-1; c++)/* we skip the first and last column */ { unsigned char* p = &data.u8TempImage[DILATION][r+c]; data.u8TempImage[EROSION][r+c] = *(p-nc-1) & *(p-nc) & *(p-nc+1) & *(p-1) & *p & *(p+1) & *(p+nc-1) & *(p+nc) & *(p+nc+1); } } //wrap image DILATION in picture struct Pic1.data = data.u8TempImage[DILATION]; Pic1.width = nc; Pic1.height = OSC_CAM_MAX_IMAGE_HEIGHT/2; Pic1.type = OSC_PICTURE_GREYSCALE; //as well as EROSION (will be used as output) Pic2.data = data.u8TempImage[EROSION]; Pic2.width = nc; Pic2.height = OSC_CAM_MAX_IMAGE_HEIGHT/2; Pic2.type = OSC_PICTURE_BINARY;//probably has no consequences //have to convert to OSC_PICTURE_BINARY which has values 0x01 (and not 0xff) OscVisGrey2BW(&Pic1, &Pic2, 0x80, false); //now do region labeling and feature extraction OscVisLabelBinary( &Pic2, &ImgRegions); OscVisGetRegionProperties( &ImgRegions); //OscLog(INFO, "number of objects %d\n", ImgRegions.noOfObjects); //plot bounding boxes both in gray and dilation image Pic2.data = data.u8TempImage[GRAYSCALE]; OscVisDrawBoundingBoxBW( &Pic2, &ImgRegions, 255); OscVisDrawBoundingBoxBW( &Pic1, &ImgRegions, 128); }
BinaryImage* GreyscaleImage::convert(BinaryImage* binary, uint8 threshold, bool darkIsForeground) { OscVisGrey2BW(&this->getOscarContext(), &binary->getOscarContext(), threshold, darkIsForeground); return binary; }