Image fading help needed C++

Pages: 123
Hi All

I am new to image processing using c++. I need to read an image pixel by pixel, then modify the image by fading it, and then the final result must be written to a new image. The new image will have the faded content. Need a way to parse and write this without using any 3rd party libraries. Which algorithm is best suited for fading an image? To fade image, I thought of taking each pixel value and take average of it and considering its nearby pixels.

Below code I tried using C. But something is wrong with this approach I feel as I am not able to get a readable image of the new file which is faded. I need a C++ code which does this functionality. Please help me on this.

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
98
#include <stdio.h>
#include <stdlib.h>


int main()
{
	FILE *fin, *fout;
	char pathin[64], pathout[64];
	char **rev, px;
	int sum, width, height, read, i, j;
	
	printf("Infile name is: ");
	scanf("%s", pathin);
	printf("Outfile name is: ");
	scanf("%s", pathout);
	
	printf("Width of image (in pixels): ");
	scanf("%d", &width);
	printf("Height of image (in pixels): ");
	scanf("%d", &height);
	
	fin = fopen(path_in, "rb");
	fout = fopen(path_out, "wb");
	
	rev = (unsigned char **)malloc(height * sizeof(unsigned char *));
	for(i = 0; i < height; i++)
		rev[i] = (unsigned char *)malloc(width * sizeof(unsigned char));
	//Store pixel values from image in a width x height unsigned char matrix
	for(i = 0; i < height; i++)
	{
		for(j = 0; j < width; j++)
		{
			read = fread(&px, sizeof(unsigned char), 1, fin);
			rev[i][j] = px;
		}
	}
	//Fade the image using average of nearby pixels
	sum = 0;
	for(i = 0; i < height; i++)
	{
		for(j = 0; j < width; j++)
		{
			//Top row of image
			if(i == 0)
			{
				if(j == 0)
					sum = (rev[i][j] + rev[i][j + 1] + 
							rev[i + 1][j] + rev[i + 1][j + 1]) / 4;
				else if(j == width - 1)
					sum = (rev[i][j] + rev[i][j - 1] +
							rev[i + 1][j] + rev[i + 1][j - 1]) / 4;
				else
					sum = (rev[i][j] + rev[i][j - 1] + rev[i][j + 1] +
							rev[i + 1][j] + rev[i + 1][j - 1] + rev[i + 1][j + 1]) / 6;
			}
			//Bottom row of image
			else if(i == height - 1)
			{
				if(j == 0)
					sum = (rev[i][j] + rev[i][j + 1] + 
							rev[i - 1][j] + rev[i - 1][j + 1]) / 4;
				else if(j == width - 1)
					sum = (rev[i][j] + rev[i][j - 1] +
							rev[i - 1][j] + rev[i - 1][j - 1]) / 4;
				else
					sum = (rev[i][j] + rev[i][j - 1] + rev[i][j + 1] +
							rev[i - 1][j] + rev[i - 1][j - 1] + rev[i - 1][j + 1]) / 6;
			}
			//Left side of image 
			else if(j == 0)
				sum = (rev[i][j] + rev[i - 1][j] + rev[i + 1][j] +
						rev[i][j + 1] + rev[i - 1][j + 1] + rev[i + 1][j + 1]) / 6;
			//Right side of image 
			else if(j == width - 1)
				sum = (rev[i][j] + rev[i - 1][j] + rev[i + 1][j] + 
						rev[i][j - 1] + rev[i - 1][j - 1] + rev[i + 1][j - 1]) / 6;
			//Pixels without border image
			else
				sum = (rev[i][j] + rev[i][j - 1] + rev[i][j + 1] + rev[i - 1][j] + rev[i + 1][j] + 
						rev[i - 1][j - 1] + rev[i - 1][j + 1] + rev[i + 1][j - 1] + rev[i + 1][j + 1]) / 9;
			rev[i][j] = (unsigned char)sum;
		}
	}
	//Write each pixel to new file
	for(i = 0; i < height; i++)
	{
		for(j = 0; j < width; j++)
		{
			if(j < width && i < height)
				fwrite(&rev[i][j], sizeof(unsigned char), 1, fout);
		}
	}
	//Close both files
	fclose(fout);
	fclose(fin);
	
	return 0;
}
what do you mean by fade? Like an old photograph?
for those, whites become yellows .. you can try increasing yellow (red and green, try decreasing blue by 10-20%) and colors look bad, maybe try (move all values toward 128 a set amount). You get random damage (grains?). You need to have a really good idea of what you want to get ... do you have a before and after? If so, you can take the difference between them (literally subtract each pixel value from the same one in the other) and study what to do from that result...

the code will be fairly easy assuming you pulled an RGB or RGBA array to work on. Its the algorithm you need.
Last edited on
I mean to smoothen the image, there by which it will look faded when compared to the original image. I want the image to look dim; thereby reducing the sharpness of the image to a certain level than the original raw image. I am not trying to make a color image to black and white image here. I want to try with some image formats which consists of twenty four bit and thirty two bits like(PNG/JPG/RGB/BMP/Targa). Should I use any filters here?
Last edited on
It sounds like you want to apply a BLUR filter.

You need to spend some time reading up on it so that your vocabulary matches what everyone else understands...

File I/O for BMP and TGA are both easy enough... but you should totally use a library to do it.
I recommend:

  • http://easybmp.sourceforge.net/
    Don't waste your time with anything else

  • https://github.com/xNWP/xTGA
    I have not played with it, but it looks good to me.
    Don't waste your time with GNU's libtga.


Hope this helps.
Last edited on
or 2 different things. It sounds like blur + color change.
driving the color components towards 128 is a start. say + or - something between 13 and 26..

I just tested it with (cp is the image bytes in 1-d, just in a loop touching every RGB value)
where adj is 13 and I think it will be rather close to what you asked for.

if(cp[i] >= 128+adj)
cp[i] = cp[i] - adj;
else
if (cp[i] <= 128-adj )
cp[i] = cp[i] + adj;
else
cp[i] = 128;
Last edited on
https://github.com/xNWP/xTGA
I have not played with it, but it looks good to me.
Don't waste your time with GNU's libtga.

Well it doesn't look good to me. I took a glance at a random file in the source code. The first line I read contained undefined behavior.

I spent 5 minutes reviewing the library. I found aliasing violations, union type punning, names containing doubled underscores. The implementation unpredictably mixes malloc and new, and the result of malloc is not checked so undefined behavior results if allocation fails.

It falls apart under even the most cursory review, can't recommend using it.
Last edited on
Well, you spent significantly more time with it than I did. Do you have another recommendation?
Sorry if my post was rude, I didn't mean to criticize you for recommending a library. It's not your fault that the library's incorrectly implemented.

I don't have any recommendations, I've never used TGA in my own software.
Hi all

I cant use any libraries here and need to parse and write the image as it is thereby making it to reduce the sharpness of the image to a certain level than the original raw image. How can this be done using c++? are there any algorithms that I can use? any samples would help here.
Hi Jonnin

did you test without using 3rd party library? Should I be using any median filter or anything else?
please share your code, so I can test it and confirm. My above code doesnt seems to work as I cant get a readable image with faded functionality.
Last edited on
Are you actually sure that you only have an array of pixels?
Bitmaps normally have a header with all informations before the actual pixel data.
I am not trying to do specific to Bitmap image here. it could be any image format provided by the user.I need to read an image pixel by pixel, then modify the image by fading it, and then the final result must be written to a modified image. What algorithm suits here? Above code doesn't work as its not readable.
Statements:
  • no third party libraries
  • read any image format supplied by user
You are wasting your life.

BMP and TGA are conveniently the waaaaaay bottom of the ladder easiest image formats to read and write, ever. So, sure, roll your own.

But if you want to bump it up a notch and read and write GIF, PNG, life just got way harder than you are ready for. JPEG/JFIF? Forget it.

Use a dang library.

@mbozzi
Heh, I wasn't trying to be rude either. Sorry it seemed like I was upset or something, I'm definitely not.

I just find it amazing how unsatisfactory the libtga implementation is...
Are there any image filter algorithms that can be applied here? I would use an image format which consists of twenty four bit and thirty two bits.
What's wrong with ImageMagick?
https://imagemagick.org/index.php

You can script it to do all sorts of image processing for you.
Hi lastchance

I cant use any such libraries or other softwares nor any scripts here.Need to write this app using standard library only from the scratch. I need to create a fade image from the original one and then upsample or downsample it.
Last edited on
it could be any image format provided by the user

and
I cant use any such libraries

you need to be an expert at this then. Just reading all those file types is a year's worth of work or more: a good number of them attempt to use various types of compression internally and jpg, j2k are rather complex, png is hard to work with, and there are dozens of subformats for some of the older ones like bmp and tga and tiff. And then there are palettes ..

you won't even start to process an image for ages, just reading the formats in will keep you busy...

ideally there would be height, width, and and one of {RGB, RGBA, C} array format you could just yank out, but it does not work like that at all for most of them.

I had an existing program that I used to test the color fade I gave you. Its 200 lines of windows crap to open and save a PNG file and extract an RGBA array from it (its actually ABGR because microsoft). The lines I gave you were the only ones that mattered. I can share it, if you want to see GDI+ gibberish wrapped around it, but it won't be useful to you (I don't even understand what all that junk is doing, its loaded with macros and type aliases and other weirdness).

Here it is, all that just for like 10 lines of RGBA loop processing code...
because of the alpha channel, I just copied the idea 3 times to test the idea. that can be cleaned up a lot. Because it was for something else, it expects filename + R G B command line input. The color isn't being used for your test.

Case in point, even all this junk was a LOT easier than writing my own PNG reader. One look at
https://en.wikipedia.org/wiki/Portable_Network_Graphics#File_format
and I ran for the hills! Lastly, I was grouchy when I wrote it... you will see what I mean.
Last edited on
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
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
/*a command line image hack program*/

//M$ falsely defines sprintf as removed from C++ without this?
#define _CRT_SECURE_NO_WARNINGS 

#include <string>
#include <windows.h>
#include <objidl.h>
#include <gdiplus.h>
#include <gdiplusgraphics.h>
#include <gdipluscolor.h>
#include "framework.h"
#include "png2.h"
using namespace Gdiplus;
#pragma comment (lib,"Gdiplus.lib")

#define MAX_LOADSTRING 100 

HINSTANCE hInst;                                // current instance
WCHAR szTitle[MAX_LOADSTRING];                  // The title bar text
WCHAR szWindowClass[MAX_LOADSTRING];            // the main window class name
HWND mhWnd;

// Forward declarations of functions included in this code module:
ATOM                MyRegisterClass(HINSTANCE hInstance);
BOOL                InitInstance(HINSTANCE, int);
LRESULT CALLBACK    WndProc(HWND, UINT, WPARAM, LPARAM);
INT_PTR CALLBACK    About(HWND, UINT, WPARAM, LPARAM);

/// this incredible function is required to save the image file as a .png file.  
///This is so convoluted M$ had to provide this code in their docs, else .save() 
///is unusuable by mere mortals. 
int GetEncoderClsid(const WCHAR* format, CLSID* pClsid)
{
    UINT  num = 0;          // number of image encoders
    UINT  size = 0;         // size of the image encoder array in bytes
    ImageCodecInfo* pImageCodecInfo = NULL;
    GetImageEncodersSize(&num, &size);
    if (size == 0)
        return -1;  // Failure
    pImageCodecInfo = (ImageCodecInfo*)(malloc(size));
    if (pImageCodecInfo == NULL)
        return -1;  // Failure
    GetImageEncoders(num, size, pImageCodecInfo);
    for (UINT j = 0; j < num; ++j)
    {
        if (wcscmp(pImageCodecInfo[j].MimeType, format) == 0)
        {
            *pClsid = pImageCodecInfo[j].Clsid;
            free(pImageCodecInfo);
            return j;  // Success
        }
    }
    free(pImageCodecInfo);
    return -1;  // Failure
}

int APIENTRY wWinMain(_In_ HINSTANCE hInstance, 
                     _In_opt_ HINSTANCE hPrevInstance,
                     _In_ LPWSTR    lpCmdLine,
                     _In_ int       nCmdShow)
{
   ///VS generated gibberish
    LoadStringW(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
    LoadStringW(hInstance, IDC_PNG2, szWindowClass, MAX_LOADSTRING);
    MyRegisterClass(hInstance);        
    nCmdShow = false; ///hide the main window, it has no value.     
    InitInstance (hInstance, nCmdShow);    
    ///---------------------------------------
    ///translate windows mess back to standard argc/argv interface
    /// because this is a windowed program, use messagebox instead of cout to talk to users
    int reqargs = 5; 
    LPWSTR* argv;
    int argc{}; 
    argv = CommandLineToArgvW(GetCommandLineW(), &argc);    
    if(argc < reqargs) ///not enough args check
      {         
        //MessageBoxA(useless pointer, message, title, 0 means OK button)
         MessageBoxA(0, "Too few arguments.  Usage: filename R G B","",0 );         
         return 0;
      }
   ///--------------------------------------------------------
   std::string stati[] ///the gdi+ errors, FWIW
   {"Ok","GenericError","InvalidParameter (file not found, wrong type?)","OutOfMemory","ObjectBusy",
    "InsufficientBuffer","NotImplemented","Win32Error","WrongState","Aborted",
    "FileNotFound","ValueOverflow","AccessDenied","UnknownImageFormat",
    "FontFamilyNotFound","FontStyleNotFound","NotTrueTypeFont",
    "UnsupportedGdiplusVersion","GdiplusNotInitialized","PropertyNotFound",
    "PropertyNotSupported","ProfileNotFound"};
   GpStatus gps{}; ///set up gdi+
   GdiplusStartupInput forizzle; 
   ULONG_PTR           token;   
   gps = GdiplusStartup(&token, &forizzle, nullptr);
   if (gps) { MessageBoxA(0, stati[gps].c_str(), "GDI Start", 0);  return 0; }
   ///load the image file.  
   Bitmap original(argv[1]);
   gps = original.GetLastStatus();
   if (gps) { MessageBoxA(0, stati[gps].c_str(), "Image Load", 0);  return 0; }

   ///process image. 
   uint8_t Rin = std::wcstol(argv[2],0,10);
   uint8_t Gin = std::wcstol(argv[3], 0, 10);
   uint8_t Bin = std::wcstol(argv[4], 0, 10);
   
   uint32_t w{ original.GetWidth()},h{ original.GetHeight()};
   Gdiplus::BitmapData data;
   Gdiplus::Rect sq(0, 0, w, h);

   ///extremely useful code showing how to get the RGBA byte data in a usable
   ///format.  
   original.LockBits(&sq,
       Gdiplus::ImageLockModeWrite, PixelFormat32bppARGB, &data);
   uint8_t * cp = (uint8_t*)(data.Scan0);
      
   char adj = 13;

   for (int i = 0; i < w * h * 4;)
   {
     i++;
      if(cp[i] >= 128+adj)
      cp[i] = cp[i] - adj;
      else
      if (cp[i] <= 128-adj )
      cp[i] = cp[i] + adj;
      else
          cp[i] = 128;
   i++;
      if (cp[i] >= 128 + adj)
          cp[i] = cp[i] - adj;
      else
          if (cp[i] <= 128 - adj)
              cp[i] = cp[i] + adj;
          else
              cp[i] = 128;
              i++;
      if (cp[i] >= 128 + adj)
          cp[i] = cp[i] - adj;
      else
          if (cp[i] <= 128 - adj)
              cp[i] = cp[i] + adj;
          else
              cp[i] = 128;
              i++;
   }

   original.UnlockBits(&data);

   /// Save the image.
    CLSID pngClsid;
    int whatsthis = GetEncoderClsid(L"image/png", &pngClsid);
    if(whatsthis == -1)
     { MessageBoxA(0, "png not supported?!", "", 0);  return 0; }
    
    ///quick and dirty new file name. 
    std::wstring nuname = argv[1];
    nuname.replace(nuname.find(L"."),10, L"_Trans.png");    
    
    gps = original.Save(nuname.c_str(), &pngClsid);
    if (gps) { MessageBoxA(0, stati[gps].c_str(), "Save", 0);  return 0; }
    GdiplusShutdown(token);
    return 0;
}

/// more windows generated nonsense. 
ATOM MyRegisterClass(HINSTANCE hInstance)
{
    WNDCLASSEXW wcex;
    wcex.cbSize = sizeof(WNDCLASSEX);
    wcex.style          = CS_HREDRAW | CS_VREDRAW;
    wcex.lpfnWndProc    = WndProc;
    wcex.cbClsExtra     = 0;
    wcex.cbWndExtra     = 0;
    wcex.hInstance      = hInstance;
    wcex.hIcon          = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_PNG2));
    wcex.hCursor        = LoadCursor(nullptr, IDC_ARROW);
    wcex.hbrBackground  = (HBRUSH)(COLOR_WINDOW+1);
    wcex.lpszMenuName   = MAKEINTRESOURCEW(IDC_PNG2);
    wcex.lpszClassName  = szWindowClass;
    wcex.hIconSm        = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL));
    return RegisterClassExW(&wcex);
}
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
   hInst = hInstance; // Store instance handle in our global variable
   HWND hWnd = CreateWindowW(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,
      CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, nullptr, nullptr, hInstance, nullptr);
   mhWnd = hWnd;
   ShowWindow(hWnd, nCmdShow);   
   return TRUE;
}
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{ return 0;}
INT_PTR CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{ return (INT_PTR)FALSE; }
//M$ falsely defines sprintf as removed from C++ without this?
#define _CRT_SECURE_NO_WARNINGS


No, the MSVC compiler tells you only that sprintf is deprecated und you should use sprintf_r sprintf_s instead.
Last edited on
Hi Jonnin

Thanks for sharing code.
Is there any way to manipulate twenty four bit and thirty two bits image formats?
Pages: 123