⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 bmpimage.cpp

📁 本程序是计算机视觉稠密匹配的程序
💻 CPP
📖 第 1 页 / 共 2 页
字号:
 * strange bitmap file that this can't handle, but the chances of finding such
 * a file this are nearly zero.
 *
 * Each row of pixels is always padded to a 4-byte boundary.
 */
int CBMPImage::readBitsUncompressed(FILE *fp, RGB *image, int width, int height,
			 int depth, RGB *colorTable)
{
    UINT8 temp;
    int   rc, padBytes, i;
    long  row, column, pixel, value;
    
    switch (depth) {
    case 1:
	/*
	 * For 1 bit per pixel, each byte is 8 pixels.  Each one is an index
	 * into the color table (1 or 0).  Most significant byte first.  All
	 * is padded to 32-bit boundaries as well.
	 */
	pixel = 0;
	if (((width % 32) == 0) || ((width % 32) > 24))
	    padBytes = 0;
	else if ((width % 32) <= 8)
	    padBytes = 3;
	else if ((width % 32) <= 16)
	    padBytes = 2;
	else
	    padBytes = 1;

	for (row = height; row > 0; row--)
	{
	    for (column = width; column > 0; column -= 8)
	    {
		rc = readUINT8little(fp, &temp);
		if (rc != 0)
		    return rc;
		for (i=0; i < ((column < 8) ? column : 8); i++)
		{
		    /*
		     * For each byte read, bit-decompose it.  Note that the
		     * last byte on a row could have less than 8 bits used.
		     * Most significant bits come first.
		     */
		    value = ((temp & (1 << (7-i))) == 0) ? 0 : 1;
		    image[pixel].red   = colorTable[value].red;
		    image[pixel].green = colorTable[value].green;
		    image[pixel].blue  = colorTable[value].blue;
		    pixel++;
		}
	    }
	    if (padBytes != 0)
	    {
		rc = fseek(fp, padBytes, SEEK_CUR);
		if (rc != 0)
		    return rc;
	    }
	}
	break;

    case 4:
	/*
	 * For 4 bits per pixel, each byte is two pixels.  The upper half go to
	 * the first pixel, and the lower half to the second.
	 */
	pixel = 0;
	if (((width % 8) == 0) || ((width % 8) > 6))
	    padBytes = 0;
	else if ((width % 8) <= 2)
	    padBytes = 3;
	else if ((width % 8) <= 4)
	    padBytes = 2;
	else
	    padBytes = 1;
	
	for (row = height; row > 0; row--)
	{
	    for (column = width; column > 0; column -= 2)
	    {
		/*
		 * Each byte here is two pixels.  Note that the last byte on a
		 * row may only contain one pixel.
		 */
		rc = readUINT8little(fp, &temp);
		if (rc != 0)
		    return rc;
		/*
		 * First pixel is the upper 4 bits
		 */
		value = temp >> 4;
		image[pixel].red   = colorTable[value].red;
		image[pixel].green = colorTable[value].green;
		image[pixel].blue  = colorTable[value].blue;
		pixel++;

		/*
		 * Second pixel is lower 4 bits.  If this is the last byte in
		 * the row, and there are an odd number of pixels per row, then
		 * this is not valid data.
		 */
		if (column == 1)
		{
		    value = temp & 0x0f;
		    image[pixel].red   = colorTable[value].red;
		    image[pixel].green = colorTable[value].green;
		    image[pixel].blue  = colorTable[value].blue;
		    pixel++;
		}
	    }
	    if (padBytes != 0)
	    {
		rc = fseek(fp, padBytes, SEEK_CUR);
		if (rc != 0)
		    return rc;
	    }
	}
	break;

    case 8:
	/*
	 * For 8 bits per pixel, each byte is one pixel.
	 */
	pixel = 0;
	padBytes = ((width % 4) == 0) ? 0 : (4 - (width % 4));

	for (row=height; row > 0; row--)
	{
	    for (column=width; column > 0; column--)
	    {
		rc = readUINT8little(fp, &temp);
		if (rc != 0)
		    return rc;
		image[pixel].red   = colorTable[temp].red;
		image[pixel].green = colorTable[temp].green;
		image[pixel].blue  = colorTable[temp].blue;
		pixel++;
	    }
	    if (padBytes != 0)
	    {
		rc = fseek(fp, padBytes, SEEK_CUR);
		if (rc != 0)
		    return rc;
	    }
	}
	break;

    case 16:
	/*
	 * For 16 bits per pixel, you must read two bytes per pixel.  But
	 * there's a catch. The data is big endian!  This is because all pixel
	 * data (for all formats, actually) is stored as a packed array,
	 * stored in pixel order.
	 */
	pixel = 0;
	padBytes = ((width % 2) == 0) ? 0 : 2;
	for (row=height; row > 0; row--)
	{
	    for (column=width; column > 0; column--)
	    {
		/*
		 * Read a 16-bit integer as big endian.  Do this by reading
		 * two bytes and mathematically combine them.  After that,
		 * proceed as usual.
		 */
		rc = readUINT8little(fp, &temp);
		if (rc != 0)
		    return rc;
		value = ((long)temp) << 8;
		rc = readUINT8little(fp, &temp);
		if (rc != 0)
		    return rc;
		value |= temp;

		image[pixel].red   = colorTable[value].red;
		image[pixel].green = colorTable[value].green;
		image[pixel].blue  = colorTable[value].blue;
		pixel++;
	    }
	    if (padBytes != 0)
	    {
		rc = fseek(fp, padBytes, SEEK_CUR);
		if (rc != 0)
		    return rc;
	    }
	}
	break;

    case 24:
	/*
	 * For 24 bits per pixel, it's an RGB structure.  Note that the color
	 * table is ignore for bit depths greater than 24 bits.
	 */
	pixel = 0;
	padBytes = width % 4;

    for (row=height; row > 0; row--)
	{
	    for (column=width; column > 0; column--)
	    {
		    rc = readRgb(fp, image+pixel, 3);
            if (rc != 0 )
                return rc;
		    pixel++;
	    }
	    if (padBytes != 0)
	    {
		rc = fseek(fp, padBytes, SEEK_CUR);
		if (rc != 0)
		    return rc;
	    }
	}          

    
    break;
    }
    
    return 0;
}


/*
 * ReadMaskBitsUncompressed.  Reads a monochrome mask into an array of
 * characters.  It assmes that there is no compression.  This is very similar
 * (internally) to the readBitsUncompressed function.  Note that if the data
 * read isn't really one-bit-deep data, you'll probably get garbage back.
 */
int CBMPImage::readMaskBitsUncompressed(FILE *fp, char *image, int width, int height)
{
    UINT8 temp;
    int   rc, padBytes, i;
    long  row, column, pixel;
    char value;
    
    /*
     * see the one-bit-depth part of readBitsUncompressed for comments
     */
    pixel = 0;
    if (((width % 32) == 0) || ((width % 32) > 24))
	padBytes = 0;
    else if ((width % 32) <= 8)
	padBytes = 3;
    else if ((width % 32) <= 16)
	padBytes = 2;
    else
	padBytes = 1;

    for (row = height; row > 0; row--)
    {
	    for (column = width; column > 0; column -= 8)
	    {
	        rc = readUINT8little(fp, &temp);
	        if (rc != 0)
    		    return rc;
	        for (i=0; i < ((column < 8) ? column : 8); i++)
	        {
		        value = ((temp & (1 << (7-i))) == 0) ? (char) 0 : (char) 1;
		        image[pixel] = value;
		        pixel++;
	        }
	    }
	    if (padBytes != 0)
	    {
	        rc = fseek(fp, padBytes, SEEK_CUR);
	        if (rc != 0)
		    return rc;
	    }
    }

    return 0;
}


/*
 * reflectYRGB takes an array of RGB vales and the dimensions they represent
 * and flips it vertically.  This will convert a bottom-left origin array to a
 * top-left origin array.
 */
void CBMPImage::reflectYRGB(RGB *image, int width, int height)
{
    int row, col;
    RGB temp;
    
    for (row = 0; row < (height / 2); row++)
    {
	    for (col = 0; col < width; col++)
	    {
	        /* Swap pixels at (x,y) with (x,height-y) */
	        memcpy(&temp, image+(row * width + col), sizeof(RGB));
	        memcpy(image+(row * width + col),
		       image+((height - row - 1) * width + col), sizeof(RGB));
	        memcpy(image+((height - row - 1) * width + col), &temp,
		       sizeof(RGB));
	    }
    }
}
/*
 * reflectYchar takes an array of char values and the dimensions they
 * represent and flips it vertically.  This will convert a bottom-left origin
 * array to a top-left origin array.
 */
void CBMPImage::reflectYchar(char *image, int width, int height)
{
    int row, col;
    char temp;
    
    for (row = 0; row < (height / 2); row++)
    {
	for (col = 0; col < width; col++)
	{
	    /* Swap values at (x,y) with (x,height-y) */
	    temp = image[row * width + col];
	    image[row * width + col]=image[(height - row - 1) * width + col];
	    image[(height - row - 1) * width + col] = temp;
	}
    }
}

/*****************************************************************************
 *
 * High-level functions
 *
 * These functions read in specific types of bitmap files.  Each assumes that
 * the file pointer is positioned at the appropriate place in a bitmap file.
 * (At the start of a BITMAPFILEHEADER for all functions except
 * readMultipleImages, which assumes the file pointer to be positioned on the
 * start of a BITMAPARRAYHEADER.  These functions will leave the file pointer
 * on the byte after the image's color table.
 *
 * The coordinate speaces in the returned arrays will have an upper-left
 * origin.   As before, a non-zero return value indicates that something went
 * wrong.
 *
 * Note that the BMP and mono-ICO functions will not return 1000 if the image
 * is of type color-icon.  This is because a color icon consists of a bitmap
 * and a monochrome icon.
 *
 * return values:
 *	   0 - success
 *	1000 - incorrect file type for the routine called
 *	1001 - image data out of range or damaged file
 *	1002 - good data, but the routine called can't handle it (yet)
 *	1003 - out of memory allocating color table
 *	1004 - out of memory allocating image
 *	1005 - out of memory allocating image arrays
 *	1006 - Illegal image type in a multi-image array
 *
 *     other - I/O error of some kind
 */


/*
 * readSingleImageBMP will read a single BMP image and generate an array of RGB
 * triples that contain the RGB values for every pixel.  It will also return
 * the dimensions of the image.
 */
int CBMPImage::readSingleImageBMP(FILE *fp, RGB **argb, UINT32 *width, UINT32 *height)
{
    BITMAPFILEHEADER  bfh;
    BITMAPHEADER      bh;
    RGB              *colorTable=NULL, *image=NULL;
    int               rc, depth, inverted;
    long              numColors, numPixels, endPos;
    
    /*
     * First, get the file header and sanity check it.  The type field must be
     * TYPE_BMP or we're aborting.
     */
    rc = readBitmapFileHeader(fp, &bfh);
    if (rc != 0)
	return rc;
    if ((bfh.type != TYPE_BMP) &&
	(bfh.type != TYPE_ICO_COLOR) &&
	(bfh.type != TYPE_PTR_COLOR))
	return 1000;
    
    /*
     * Immediately following a file header is always the bitmap header.  Read
     * it.  Sanity check any values we might need.  Specifically, less than
     * 32-bit depth, known compression scheme, known origin, and known color
     * encoding, and valid height/width.  Note that negative height is OK,
     * that indicates an upper-left origin for a Windows bitmap.
     */
    rc = readBitmapHeader(fp, &bh);
    if (rc != 0)
	return rc;
    depth = bh.numBitPlanes * bh.numBitsPerPlane;
    if ((depth > 32) ||
	(bh.compressionScheme > COMPRESSION_LAST) ||
	(bh.origin > ORIGIN_LAST) ||
	(bh.colorEncoding > COLOR_ENCODING_LAST) ||
	(bh.width < 1) ||
	(bh.height == 0))
	return 1001;
    
    /*
     * If the height is negative, then this is a Windows bitmap whose origin
     * is the upper-left corner and not the lower-left.  The inverted flag
     * indicates a lower-left origin.  Our code will be outputting an
     * upper-left origin pixel array.
     */
    if (bh.height < 0)
    {
	inverted = 0;
	bh.height = -bh.height;
    }
    else
	inverted = 1;
    
    /*
     * Now, sanity check a few fields that are valid, but I don't have code to
     * deal with them yet.  This includes: more than one bit plane, any
     * compression scheme, and bit depths that are not 1, 4, 8, 16, or 24.
     */
    if ((bh.numBitPlanes > 1) ||
	((bh.numBitsPerPlane != 1) &&
	 (bh.numBitsPerPlane != 4) &&
	 (bh.numBitsPerPlane != 8) &&
	 (bh.numBitsPerPlane != 16) &&
	 (bh.numBitsPerPlane != 24)) ||
	(bh.compressionScheme != COMPRESSION_NONE))
	return 1002;
    
    /*
     * Allocate and read the color table.  The file pointer has been
     * positioned in the right place by the readBitmapHeader function.  Note
     * that images with 24-bits or more color depth have no color table.  They
     * are  already RGB.  When reading the color table, be sure to check for
     * old/new format bitmaps. 
     */
    if (depth < 24)
    {
	numColors = 1 << depth;
	colorTable = new RGB[numColors]; // (RGB *)calloc(numColors, sizeof(RGB));
	if (colorTable == NULL)
	    return 1003;
    memset(colorTable, 0, numColors * sizeof(RGB));
	if (bh.size <= 12)
	    rc = readColorTable(fp, colorTable, numColors, 3);
	else
	    rc = readColorTable(fp, colorTable, numColors, 4);
	if (rc != 0)
	{
	    delete [] (colorTable);
	    return rc;
	}
    }
    
    /*
     * We're at the end of the color table.  Preserve this position.  We'll
     * need to leave the file pointer there before returning from this
     * function. 
     */
    endPos = ftell(fp);

    /*
     * Allocate the array of pixels and fill it in.
     */
    numPixels = bh.width * bh.height;
    image = new RGB[numPixels]; //(RGB *)calloc(numPixels, sizeof(RGB));
    if (image == NULL)
    {
	delete []  (colorTable);
	return 1004;
    }
    memset(image, 0, numPixels * sizeof(RGB));
    
    /*
     * Seek to the bits
     */
    rc = fseek(fp, bfh.offsetToBits, SEEK_SET);
    if (rc != 0)
    {
	delete []  (colorTable);
	delete []  (image);
	return rc;
    }
    
    /*
     * Read the bits.  If code for decompressing bits should be written,
     * insert the call here.
     */
    switch (bh.compressionScheme) {
    case COMPRESSION_NONE:
	rc = readBitsUncompressed(fp, image, bh.width, bh.height, depth,
				  colorTable);
	break;
    }
    
    if (rc != 0)
    {
	delete [] (image);
	return rc;
    }
    
    /*
     * If the origin is lower-left, flip the image upside down
     */
    if (inverted)
	reflectYRGB(image, bh.width, bh.height);

    /*
     * Return the output values.  Set the file pointer to the byte after the
     * color table.
     */
    *argb = image;
    *width = bh.width;
    *height = bh.height;
    fseek(fp, endPos, SEEK_SET);

    /*
     * Clean up and return.  Note that we don't return the color table.  This
     * is because we're returning an array of RGB values for the image - such
     * a table would be redundant.
     */
    if (colorTable != NULL)
	delete [] (colorTable);
    
    return 0;
}

bool CBMPImage::LoadFile(const char *pszBMPFile)
{
    FILE* fp = fopen(pszBMPFile, "rb");
    if (NULL == fp)
    {
        return false;
    }
    if (0 == readSingleImageBMP(fp, 
                                (RGB**) &m_pRGBArray, 
                                (UINT32*) &m_iWidth, 
                                (UINT32*) &m_iHeight))
    {
        fclose(fp);
        return true;
    }
    else
    {
        fclose(fp);
        return false;
    }
}

CBMPImage::CBMPImage()
{
}

CBMPImage::~CBMPImage()
{
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -