#include #include "CBitmap.h" uchar CBitmap::nOnes[256]; uchar CBitmap::oneShift[8]; // table of bit values #define FWRITE(p,s,f) if (fwrite(p, 1, s, f) != (size_t) s) { printf("File write error\n"); exit(-1); } #define FREAD(p,s,f) if (fread(p, 1, s, f) != (size_t) s) { printf("File read error\n"); exit(-1); } /* Makes an empty bitmap. */ CBitmap::CBitmap() { nRows = nCols = bytesRow = 0; data = 0; initOnes(); }; /* Creat a bitmap from a openCV Mat. Bitmap pixels are set to 1, if the Mat pixel is equal to match. Every other value is set to 0. */ CBitmap::CBitmap(Mat m, uchar match) { CV_Assert(m.depth() == CV_8U); initOnes(); nRows = m.rows; nCols = m.cols; bytesRow = (nCols + 7) / 8; data = (uchar *) malloc(nRows * bytesRow); if (!data) { printf("CBitmap, malloc failed.\n"); exit(-1); } uchar* r = data - 1; for (int iy = 0; iy < nRows; iy++) { uchar* p = m.ptr(iy); for (int ix = 0; ix < nCols; ix++) { if ((ix & 7) == 0) { // new byte? r++; *r = 0; } if (*p++ == match) *r |= oneShift[ix & 7]; // little endian } } }; /* Create and read a bitmap from the open file f. */ CBitmap::CBitmap(FILE* f) { FREAD(&nRows, sizeof(nRows), f); FREAD(&nCols, sizeof(nCols), f); if (nRows <= 0 || nRows > 1024 || nCols <= 0 || nCols > 1024) { // sanity check printf("Reading, somethings fishy, nr %d, nc %d\n", nRows, nCols); exit(-1); } bytesRow = (nCols + 7) / 8; data = (uchar*)malloc(nRows * bytesRow); if (!data) { printf("CBitmap, malloc failed.\n"); exit(-1); } FREAD(data, nRows * bytesRow, f); } void CBitmap::initOnes() // initialize the table of bits / value & ones shifted. { // printf("initOnes()\n"); if (nOnes[1] == 1) return; // already inited? for (int i = 0; i < 8; i++) oneShift[i] = 1 << i; // table of bit positions for (int i = 0; i < 256; i++) { // for each byte, get # of 1's int n = 0; for (int j = 0; j < 8; j++) n += (i & (1 << j)) != 0; nOnes[i] = n; } } #if 0 /* *** Correlation coefficient of two bitmaps. ***/ float CBitmap::correlate(CBitmap cb2, bool fromTop) { int nr = MIN(nRows, cb2.nRows); int nc = MIN(nCols, cb2.nCols); int ncMax = MAX(nCols, cb2.nCols); // width of larger image int nbytes = (nc + 7) / 8; // bytes per row of smaller int ncMaxBytes = (ncMax + 7) / 8; int iy1 = 0, iy2 = 0; if (!fromTop) { iy1 = nRows - nr; iy2 = cb2.nRows - nr; } int total = 0; for (int iy = 0; iy < nr; iy++, iy1++, iy2++) { uchar* p1 = data + iy1 * bytesRow; uchar* p2 = cb2.data + iy2 * cb2.bytesRow; int ix; for (ix = 0; ix < nbytes; ix++, p1++, p2++) { // sum common columns total += nOnes[*p1 ^ *p2]; // sum # of different bits } if (cb2.nCols > nCols) { // count the 1's in the wider image as not matching for (; ix < ncMaxBytes; ix++, p2++) total += nOnes[*p2]; } else { for (; ix < ncMaxBytes; ix++, p1++) total += nOnes[*p1]; } } return (float) 1.0 - (float)total / (float)(nr * ncMax); } #endif /* *** Correlation coefficient of two binary bitmaps. *** This coefficient is defined as the number of pixels that match divided by the number if pixels in the shorter, wider bitmap. If fromTop is set, matching starts at the top row of each image. Otherwise, matching starts at the bottom row. Rows of the taller image are scaled to match those of the shorter. */ float CBitmap::correlate(CBitmap cb2, bool fromTop) { int nr = MIN(nRows, cb2.nRows); int nc = MIN(nCols, cb2.nCols); int ncMax = MAX(nCols, cb2.nCols); // width of larger image int nbytes = (nc + 7) / 8; // bytes per row of smaller int ncMaxBytes = (ncMax + 7) / 8; int total = 0; uchar* p1, * p2; for (int iy = 0; iy < nr; iy++) { if (nRows >= cb2.nRows) { // scale vertically p2 = cb2.data + iy * cb2.bytesRow; p1 = data + ((iy * nRows) / cb2.nRows) * bytesRow; } else { p1 = data + iy * bytesRow; p2 = cb2.data + ((iy * cb2.nRows) / nRows) * cb2.bytesRow; } int ix; for (ix = 0; ix < nbytes; ix++, p1++, p2++) { // sum common columns total += nOnes[*p1 ^ *p2]; // sum # of different bits } if (cb2.nCols > nCols) { // count the 1's in the wider image as not matching for (; ix < ncMaxBytes; ix++, p2++) total += nOnes[*p2]; } else { for (; ix < ncMaxBytes; ix++, p1++) total += nOnes[*p1]; } } return (float)1.0 - (float)total / (float)(nr * ncMax); } Mat CBitmap::b2Mat() // convert to bitmap to CV Mat. { Mat g = Mat(nRows, nCols, CV_8UC1); uchar* p0 = data; for (int iy = 0; iy < nRows; iy++) { uchar* p1 = g.ptr(iy); for (int ix = 0; ix < nCols; ix++) *p1++ = p0[ix / 8] & oneShift[ix & 7] ? 255 : 0; p0 += bytesRow; } return g; } /* Write the bitmap to the open file */ int CBitmap::write(FILE* f) { FWRITE(&nRows, sizeof(nRows), f); FWRITE(&nCols, sizeof(nCols), f); FWRITE(data, nRows*bytesRow, f); return 1; }