Subtracting pixel values from two different bmp files

I would like to subtract one image from another to get something like "differential picture" (i am not sure whether the name is correct). I've managed to read the FILEHEADER and FILEINFOHEADER of bitmap. I will subtract 24-bit bmp files only. However i can't understand the structure of this file. So far my code looks like this. Could you please point me or give an example of at least copying one bmp file to a new one? This example would be useful, because subtracting will be simillar, instead of copying the pixel value i will just put abs(value1-value2) in the output.

Code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
// ConsoleApplication1.cpp : Defines the entry point for the console application.
#include "stdafx.h"
#include <iostream>
#include <fstream>
    
    
using namespace std;
    
struct BITMAPfileHEADER
{
    unsigned short bfType;
    unsigned int   bfSize;
    unsigned short bfReserved1;
    unsigned short bfReserved2;
    unsigned int   bfOffBits;
};
    
    
struct BITMAPinfoHEADER
{
    unsigned int biSize;
    unsigned int biWidth;
    unsigned int biHeight;
    unsigned short biPlanes;
    unsigned short biBitCount;
    unsigned int biCompression;
    unsigned int biSizeImage;
    unsigned int biXpelsPerMeter;
    unsigned int biYpelsPerMeter;
    unsigned int biClrUses;
    unsigned int biClrImportant;
};

int readBFH(ifstream &ifs, BITMAPfileHEADER &bfh)
{
    ifs.read(reinterpret_cast<char *>(&bfh.bfType), 2);
    ifs.read(reinterpret_cast<char *>(&bfh.bfSize), 4);
    ifs.read(reinterpret_cast<char *>(&bfh.bfReserved1), 2);
    ifs.read(reinterpret_cast<char *>(&bfh.bfReserved2), 2);
    ifs.read(reinterpret_cast<char *>(&bfh.bfOffBits), 4);
    return ifs.tellg();
}

int readBIH(ifstream &ifs, BITMAPinfoHEADER &bih)
{
    ifs.read(reinterpret_cast<char *>(&bih.biSize), 4);
    ifs.read(reinterpret_cast<char *>(&bih.biWidth), 4);
    ifs.read(reinterpret_cast<char *>(&bih.biHeight), 4);
    ifs.read(reinterpret_cast<char *>(&bih.biPlanes), 2);
    ifs.read(reinterpret_cast<char *>(&bih.biBitCount), 2);
    ifs.read(reinterpret_cast<char *>(&bih.biCompression), 4);
    ifs.read(reinterpret_cast<char *>(&bih.biSizeImage), 4);
    ifs.read(reinterpret_cast<char *>(&bih.biXpelsPerMeter), 4);
    ifs.read(reinterpret_cast<char *>(&bih.biYpelsPerMeter), 4);
    ifs.read(reinterpret_cast<char *>(&bih.biClrUses), 4);
    ifs.read(reinterpret_cast<char *>(&bih.biClrImportant), 4);    
    return ifs.tellg();
}
    
unsigned char* readPictureData(ifstream &ifs, unsigned int size, int cursor)
{
    ifs.seekg(cursor, ios::beg);
    unsigned char *picture = new unsigned char[size];
    ifs.read(reinterpret_cast<char *>(picture), size);
    return picture;
}
    
int main()
{
    BITMAPfileHEADER bfh_warm;
    BITMAPfileHEADER bfh_cold;    

    BITMAPinfoHEADER bih_warm;
    BITMAPinfoHEADER bih_cold;

    int cursor_warm;
    int cursor_cold;

    ifstream ifs_warm("1.bmp", ios::binary);
    ifstream ifs_cold("2.bmp", ios::binary);
    ofstream ofs_differential("differential.bmp", ofstream::binary);
    
    cursor_warm = readBFH(ifs_warm, bfh_warm);
    cursor_warm = readBIH(ifs_warm, bih_warm);
    cursor_cold = readBFH(ifs_cold, bfh_cold);
    cursor_cold = readBIH(ifs_cold, bih_cold);
    unsigned char* picture = readPictureData(ifs_warm, bfh_warm.bfSize - bfh_warm.bfOffBits,     cursor_warm);


    ofs_differential.write((char*)&bfh_warm, 14); //write header
    ofs_differential.write((char*)&bih_warm, 40); //write header
    //	ofs_differential.write((char*)&picture, (bfh_warm.bfSize - bfh_warm.bfOffBits)/3); //THIS DOESNT WORK
    ifs_warm.close();
    ifs_warm.close();
    ofs_differential.close();
    return 0;
}
Last edited on
I'm sure there is a 3rd party library that can do that.
What you have nearly works. All I had to change was adding #pragma pack(1) before the struct definitions (without it the bitmap file header is packed to 16 bytes), and change the unsigned char*s to char*s and removed the divide by 3.
My code looks like this now:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
// ConsoleApplication1.cpp : Defines the entry point for the console application.
#include "stdafx.h"
#include <iostream>
#include <fstream>
    
    
using namespace std;
#pragma pack(1)    
struct BITMAPfileHEADER
{
    unsigned short bfType;
    unsigned int   bfSize;
    unsigned short bfReserved1;
    unsigned short bfReserved2;
    unsigned int   bfOffBits;
};
    
    
struct BITMAPinfoHEADER
{
    unsigned int biSize;
    unsigned int biWidth;
    unsigned int biHeight;
    unsigned short biPlanes;
    unsigned short biBitCount;
    unsigned int biCompression;
    unsigned int biSizeImage;
    unsigned int biXpelsPerMeter;
    unsigned int biYpelsPerMeter;
    unsigned int biClrUses;
    unsigned int biClrImportant;
};

int readBFH(ifstream &ifs, BITMAPfileHEADER &bfh)
{
    ifs.read(reinterpret_cast<char *>(&bfh.bfType), 2);
    ifs.read(reinterpret_cast<char *>(&bfh.bfSize), 4);
    ifs.read(reinterpret_cast<char *>(&bfh.bfReserved1), 2);
    ifs.read(reinterpret_cast<char *>(&bfh.bfReserved2), 2);
    ifs.read(reinterpret_cast<char *>(&bfh.bfOffBits), 4);
    return ifs.tellg();
}

int readBIH(ifstream &ifs, BITMAPinfoHEADER &bih)
{
    ifs.read(reinterpret_cast<char *>(&bih.biSize), 4);
    ifs.read(reinterpret_cast<char *>(&bih.biWidth), 4);
    ifs.read(reinterpret_cast<char *>(&bih.biHeight), 4);
    ifs.read(reinterpret_cast<char *>(&bih.biPlanes), 2);
    ifs.read(reinterpret_cast<char *>(&bih.biBitCount), 2);
    ifs.read(reinterpret_cast<char *>(&bih.biCompression), 4);
    ifs.read(reinterpret_cast<char *>(&bih.biSizeImage), 4);
    ifs.read(reinterpret_cast<char *>(&bih.biXpelsPerMeter), 4);
    ifs.read(reinterpret_cast<char *>(&bih.biYpelsPerMeter), 4);
    ifs.read(reinterpret_cast<char *>(&bih.biClrUses), 4);
    ifs.read(reinterpret_cast<char *>(&bih.biClrImportant), 4);    
    return ifs.tellg();
}
    
char* readPictureData(ifstream &ifs, unsigned int size, int cursor)
{
    ifs.seekg(cursor, ios::beg);
    char *picture = new char[size];
    ifs.read(reinterpret_cast<char *>(picture), size);
    return picture;
}
    
int main()
{
    BITMAPfileHEADER bfh_warm;
    BITMAPfileHEADER bfh_cold;    

    BITMAPinfoHEADER bih_warm;
    BITMAPinfoHEADER bih_cold;

    int cursor_warm;
    int cursor_cold;

    ifstream ifs_warm("1.bmp", ios::binary);
    ifstream ifs_cold("2.bmp", ios::binary);
    ofstream ofs_differential("differential.bmp", ofstream::binary);
    
    cursor_warm = readBFH(ifs_warm, bfh_warm);
    cursor_warm = readBIH(ifs_warm, bih_warm);
    cursor_cold = readBFH(ifs_cold, bfh_cold);
    cursor_cold = readBIH(ifs_cold, bih_cold);
    char* picture = readPictureData(ifs_warm, bfh_warm.bfSize - bfh_warm.bfOffBits,     cursor_warm);


    ofs_differential.write((char*)&bfh_warm, 14); //write header
    ofs_differential.write((char*)&bih_warm, 40); //write header
    ofs_differential.write((char*)&picture, (bfh_warm.bfSize - bfh_warm.bfOffBits));
    ifs_warm.close();
    ifs_warm.close();
    ofs_differential.close();
    return 0;
}

On windows (Visual studio 2013) i get something like this:
And while compiling i get error that
Unhandled exception at 0x52093442 (msvcr120d.dll) in ConsoleApplication1.exe: 0xC0000005: Access violation reading location 0x004A0000.

when the program runs this line
ofs_differential.write((char*)&picture, (bfh_warm.bfSize - bfh_warm.bfOffBits));

When i compile it in code::blocks on my ubuntu 14.04 it works fine, but after creating the bitmap when i try to open it i see an error "incorrect file header" or something like that.
Last edited on
Doesn't seem to like casting the address of a char* to a char*, try removing the cast in the ofs_differential.write(...).
Topic archived. No new replies allowed.