Click here to Skip to main content
Click here to Skip to main content

Convolution of Bitmaps

By , 29 Mar 2006
 

Introduction

Image convolution plays an important role in computer graphics applications. Convolution of images allows for image alterations that enable the creation of new images from old ones. Convolution also allows for important features such as edge detection, with many widespread uses. The convolution of an image is a simple process by which the pixel of an image is multiplied by a kernel, or masked, to create a new pixel value. Convolution is commonly referred to as filtering.

Details

First, for a given pixel (x,y), we give a weight to each of the surrounding pixels. It may be thought of as giving a number telling how important the pixel is to us. The number may be any integer or floating point number, though I usually stick to floating point since floats will accept integers as well. The kernel or mask that contains the filter may actually be any size (3x3, 5x5, 7x7); however, 3x3 is very common. Since the process for each is the same, I will concentrate only on the 3x3 kernels.

Second, the actual process of convolution involves getting each pixel near a given pixel (x,y), and multiplying each of the pixel's channels by the weighted kernel value. This means that for a 3x3 kernel, we would multiply the pixels like so:

(x-1,y-1)       *       kernel_value[row0][col0]
(x  ,y-1)       *       kernel_value[row0][col1]
(x+1,y-1)       *       kernel_value[row0][col2]
(x-1,y  )       *       kernel_value[row1][col0]
(x  ,y  )       *       kernel_value[row1][col1]
(x+1,y  )       *       kernel_value[row1][col2]
(x-1,y+1)       *       kernel_value[row2][col0]
(x  ,y+1)       *       kernel_value[row2][col1]
(x+1,y+1)       *       kernel_value[row2][col2]

The process is repeated for each channel of the image. This means that the red, green, and blue color channels (if working in RGB color space) must each be multiplied by the kernel values. The kernel position is related to the pixel position it is multiplied by. Simply put, the kernel is allocated in kernel[rows][cols], which would be kernel[3][3] in this case. The 3x3 (5x5 or 7x7, if using a larger kernel) area around the pixel (x,y) is then multiplied by the kernel to get the total sum. If we were working with a 100x100 image, allocated as image[100][100], and we wanted the value for pixel (10,10), the process for each channel would look like:

float fTotalSum =
 Pixel(10-1,10-1)       *       kernel_value[row0][col0] +
 Pixel(10  ,10-1)       *       kernel_value[row0][col1] +
 Pixel(10+1,10-1)       *       kernel_value[row0][col2] +
 Pixel(10-1,10  )       *       kernel_value[row1][col0] +
 Pixel(10  ,10  )       *       kernel_value[row1][col1] +
 Pixel(10+1,10  )       *       kernel_value[row1][col2] +
 Pixel(10-1,10+1)       *       kernel_value[row2][col0] +
 Pixel(10  ,10+1)       *       kernel_value[row2][col1] +
 Pixel(10+1,10+1)       *       kernel_value[row2][col2] +

Finally, each value is added to the total sum, which is then divided by the total weight of the kernel. The kernel's weight is given by adding each value contained in the kernel. If the value is zero or less, then a weight of 1 is given to avoid a division by zero.

The actual code to convolve an image is:

for (int i=0; i <= 2; i++)//loop through rows
{
    for (int j=0; j <= 2; j++)//loop through columns
    {
        //get pixel near source pixel
        /*
        if x,y is source pixel then we loop through and
        get pixels at coordinates:
        x-1,y-1
        x-1,y
        x-1,y+1
        x,y-1
        x,y
        x,y+1
        x+1,y-1
        x+1,y
        x+1,y+1
        */
        COLORREF tmpPixel = pDC->GetPixel(sourcex+(i-(2>>1)),
                                              sourcey+(j-(2>>1)));
        //get kernel value
        float fKernel = kernel[i][j];
        //multiply each channel by kernel value, and add to sum
        //notice how each channel is treated separately
        rSum += (GetRValue(tmpPixel)*fKernel);
        gSum += (GetGValue(tmpPixel)*fKernel);
        bSum += (GetBValue(tmpPixel)*fKernel);
        //add the kernel value to the kernel sum
        kSum += fKernel;
    }
}
//if kernel sum is less than 0, reset to 1 to avoid divide by zero
if (kSum <= 0)
    kSum = 1;
//divide each channel by kernel sum
rSum/=kSum;
gSum/=kSum;
bSum/=kSum;

The source code included performs some common image convolutions. Also included is a Convolve Image menu option that allows users to enter their own kernel. Common 3x3 kernels include:

gaussianBlur[3][3] = {0.045, 0.122, 0.045, 0.122, 
  0.332, 0.122, 0.045, 0.122, 0.045};
gaussianBlur2[3][3] = {1, 2, 1, 2, 4, 2, 1, 2, 1};
gaussianBlur3[3][3] = {0, 1, 0, 1, 1, 1, 0, 1, 0};
unsharpen[3][3] = {-1, -1, -1, -1, 9, -1, -1, -1, -1};
sharpness[3][3] = {0,-1,0,-1,5,-1,0,-1,0};
sharpen[3][3] = {-1, -1, -1, -1, 16, -1, -1, -1, -1};
edgeDetect[3][3] = {-0.125, -0.125, -0.125, -0.125, 
  1, -0.125, -0.125, -0.125, -0.125};
edgeDetect2[3][3] = {-1, -1, -1, -1, 8, -1, -1, -1, -1};
edgeDetect3[3][3] = {-5, 0, 0, 0, 0, 0, 0, 0, 5};
edgeDetect4[3][3] = {-1, -1, -1, 0, 0, 0, 1, 1, 1};
edgeDetect5[3][3] = {-1, -1, -1, 2, 2, 2, -1, -1, -1};
edgeDetect6[3][3] = {-5, -5, -5, -5, 39, -5, -5, -5, -5};
sobelHorizontal[3][3] = {1, 2, 1, 0, 0, 0, -1, -2, -1 };
sobelVertical[3][3] = {1, 0, -1, 2, 0, -2, 1, 0, -1 };
previtHorizontal[3][3] = {1, 1, 1, 0, 0, 0, -1, -1, -1 };
previtVertical[3][3] = {1, 0, -1, 1, 0, -1, 1, 0, -1};
boxBlur[3][3] = {0.111f, 0.111f, 0.111f, 0.111f, 
  0.111f, 0.111f, 0.111f, 0.111f, 0.111f};
triangleBlur[3][3] = { 0.0625, 0.125, 0.0625, 
  0.125, 0.25, 0.125, 0.0625, 0.125, 0.0625};

Last but not least is the ability to show a convoluted image as a grayscale result. In order to display a filtered image as grayscale, we just add a couple lines to the bottom of the Convolve function:

//return new pixel value
if (bGrayscale)
{
    int grayscale=0.299*rSum + 0.587*gSum + 0.114*bSum;
    rSum=grayscale;
    gSum=grayscale;
    bSum=grayscale;
}

clrReturn = RGB(rSum,gSum,bSum);

This means that the entire Convolve function now looks like:

COLORREF CImageConvolutionView::Convolve(CDC* pDC, int sourcex, 
    int sourcey, float kernel[3][3], int nBias,BOOL bGrayscale)
{
    float rSum = 0, gSum = 0, bSum = 0, kSum = 0;
    COLORREF clrReturn = RGB(0,0,0);
    for (int i=0; i <= 2; i++)//loop through rows
    {
        for (int j=0; j <= 2; j++)//loop through columns
        {
            //get pixel near source pixel
            /*
            if x,y is source pixel then we loop 
            through and get pixels at coordinates:
            x-1,y-1
            x-1,y
            x-1,y+1
            x,y-1
            x,y
            x,y+1
            x+1,y-1
            x+1,y
            x+1,y+1
            */
            COLORREF tmpPixel = pDC->GetPixel(sourcex+(i-(2>>1)),
                sourcey+(j-(2>>1)));
            //get kernel value
            float fKernel = kernel[i][j];
            //multiply each channel by kernel value, and add to sum
            //notice how each channel is treated separately
            rSum += (GetRValue(tmpPixel)*fKernel);
            gSum += (GetGValue(tmpPixel)*fKernel);
            bSum += (GetBValue(tmpPixel)*fKernel);
            //add the kernel value to the kernel sum
            kSum += fKernel;
        }
    }
    //if kernel sum is less than 0, reset to 1 to avoid divide by zero
    if (kSum <= 0)
        kSum = 1;
    //divide each channel by kernel sum
    rSum/=kSum;
    gSum/=kSum;
    bSum/=kSum;
    //add bias if desired
    rSum += nBias;
    gSum += nBias;
    bSum += nBias;
    //prevent channel overflow by clamping to 0..255
    if (rSum > 255)
        rSum = 255;
    else if (rSum < 0)
        rSum = 0;
    if (gSum > 255)
        gSum = 255;
    else if (gSum < 0)
        gSum = 0;
    if (bSum > 255)
        bSum = 255;
    else if (bSum < 0)
        bSum = 0;
    //return new pixel value
    if (bGrayscale)
    {
        int grayscale=0.299*rSum + 0.587*gSum + 0.114*bSum;
        rSum=grayscale;
        gSum=grayscale;
        bSum=grayscale;
    }

    clrReturn = RGB(rSum,gSum,bSum);
    return clrReturn;
}

Last but not least, I did a little tweaking to get the program to load a default image from a resource (IDB_BITMAP1). Then, I added the ability to convolve this default image. The program will still load image from a file, the only difference is that it will now show a default image at startup.

Please note that this article is, by no means, an example of fast processing of pixels. It is merely meant to show how convolution can be done on images. If you would like a more advanced image processor, then feel free to email me with the subject "WANT CODE:ImageEdit Please". That is an unreleased image processor I have done, though parts are not implemented yet due to lack of time, that contains much more functionality, using the CxImage library as its basis for reading and saving images.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here

About the Author

Fred Ackers
Web Developer
United States United States
Member
Programming using MFC and ATL for almost 12 years now. Currently studying Operating System implementation as well as Image processing. Previously worked on DSP and the use of FFT for audio application. Programmed using ADO, ODBC, ATL, COM, MFC for shell interfacing, databasing tasks, Internet items, and customization programs.

Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
You must Sign In to use this message board.
Search this forum  
    Spacing  Noise  Layout  Per page   
Question24 bit RGBmemberñoqui4 Apr '06 - 4:00 
How can i filter a 24bit RGB BMP.file in a way where pixels almost red convert into a complete red pixels, pixels almost blue convert into complete blue pixels, and pixels almost green convert into a complete green pixels. When i mean a pixel is almost a color it means that allows the colum of the color to be(255-10%) and the other two colums to be upto(0+10%) and upto(0+10%) what in numbers means (255-25) (25) (25) what would be then (230) (25) (25). The output file must be 24 bit RGB bmp.
 
Thanks a lot.
 
noqui
 
-- modified at 20:38 Tuesday 4th April, 2006
AnswerRe: 24 bit RGBmemberFred Ackers13 Apr '06 - 4:03 
ñoqui wrote:
almost red convert into a complete red pixels

 
In order to do this, you would have to build your own filter function. This might look something like:
for (int x =0; x = 230) && (img[x][y].blue <= 25) && (img[x][y].green <= 25))
{
img[x][y].red = 255;
img[x][y].blue = img[x][y].green = 0;
}
//repeat for blue and green color options
}

 
Nothing is impossible, It's merely a matter of finding an answer to the question of HOW? ... And answering that question is usually the most difficult part of the job!!!
GeneralRe: 24 bit RGBmemberñoqui13 Apr '06 - 4:40 
Then it must look something like this:
 
for (int x =0; x for(int y=0; y < height; y++)
{
if ((img[x][y].red >= 230) && (img[x][y].blue <= 25) && (img[x][y].green <= 25))
{
img[x][y].red = 255;
img[x][y].blue = img[x][y].green = 0;
}
 
if ((img[x][y].blue >= 230) && (img[x][y].red <= 25) && (img[x][y].green <= 25))
{
img[x][y].blue = 255;
img[x][y].red = img[x][y].green = 0;
}
if ((img[x][y].green >= 230) && (img[x][y].blue <= 25) && (img[x][y].red <= 25))
{
img[x][y].green = 255;
img[x][y].blue = img[x][y].red = 0;
}
}
 
Thanks a lot FRED, i will try it.
From Argentina, noqui

QuestionDoes not compile in MSVC 2003memberDark Alchemist6 Jan '06 - 8:27 
Compiling...
StdAfx.cpp
WINVER not defined. Defaulting to 0x0501 (Windows XP and Windows .NET Server)
Compiling...
MainFrm.cpp
MainFrm.cpp(110) : warning C4244: '=' : conversion from 'int' to 'float', possible loss of data
MainFrm.cpp(111) : warning C4244: '=' : conversion from 'int' to 'float', possible loss of data
MainFrm.cpp(112) : warning C4244: '=' : conversion from 'int' to 'float', possible loss of data
MainFrm.cpp(113) : warning C4244: '=' : conversion from 'int' to 'float', possible loss of data
MainFrm.cpp(114) : warning C4244: '=' : conversion from 'int' to 'float', possible loss of data
MainFrm.cpp(115) : warning C4244: '=' : conversion from 'int' to 'float', possible loss of data
MainFrm.cpp(116) : warning C4244: '=' : conversion from 'int' to 'float', possible loss of data
MainFrm.cpp(117) : warning C4244: '=' : conversion from 'int' to 'float', possible loss of data
MainFrm.cpp(118) : warning C4244: '=' : conversion from 'int' to 'float', possible loss of data
ImageConvolutionView.cpp
ImageConvolutionView.cpp(248) : warning C4244: 'initializing' : conversion from 'double' to 'int', possible loss of data
ImageConvolutionView.cpp(249) : warning C4244: '=' : conversion from 'int' to 'float', possible loss of data
ImageConvolutionView.cpp(250) : warning C4244: '=' : conversion from 'int' to 'float', possible loss of data
ImageConvolutionView.cpp(251) : warning C4244: '=' : conversion from 'int' to 'float', possible loss of data
ImageConvolutionDoc.cpp
ImageConvolution.cpp
ImageConvolution.cpp(58) : warning C4996: 'CWinApp::Enable3dControls' was declared deprecated
C:\Program Files\Microsoft Visual Studio .NET 2003\Vc7\atlmfc\include\afxwin.h(4369) : see declaration of 'CWinApp::Enable3dControls'
ConvolveDlg.cpp
ConvolveDlg.cpp(18) : error C2143: syntax error : missing ')' before ','
ConvolveDlg.cpp(18) : error C2365: 'IDD' : redefinition; previous definition was a 'enumerator'
c:\unzipped\ImageConvolution\ConvolveDlg.h(21) : see declaration of 'IDD'
ConvolveDlg.cpp(18) : error C2244: 'IDD' : unable to match function definition to an existing declaration
c:\unzipped\ImageConvolution\ConvolveDlg.h(21) : see declaration of 'IDD'
definition
'IDD'
existing declarations
ConvolveDlg.cpp(18) : error C2059: syntax error : ')'
ConvolveDlg.cpp(20) : error C2143: syntax error : missing ';' before '{'
ConvolveDlg.cpp(20) : error C2447: '{' : missing function header (old-style formal list?)
Generating Code...
 
Build log was saved at "file://c:\unzipped\ImageConvolution\Release\BuildLog.htm"
ImageConvolution - 6 error(s), 14 warning(s)

 
That says it all for MSVC .NET 2003 (7.1). So, how do I get this thing compiled?
AnswerRe: Does not compile in MSVC 2003memberAqiruse29 Mar '06 - 9:08 
Please download the updated version, which includes corrections to for MSVC 2003
 
Nothing is impossible, It's merely a matter of finding an answer to the question of HOW? ... And answering that question is usually the most difficult part of the job!!!
Questionplease , help ?memberdynamica1231 Oct '05 - 22:03 
I want to crop a region from the image programmatically after transforming it to grayscale ?
GeneralTerriblememberChristian Graus30 Mar '05 - 16:02 
Two problems I see here
 
1. You're using GetPixel/SetPixel. This is incredibly slow
 
2. You're accessing an image via a DC. This means it's device dependant, which means no matter what it is on disc, it's going to be the bit depth of the screen.
 
If you use a DIBSection, then you can get around both these issues.

One more - it looks to me like the function you're showing needs to be called for each pixel - this is another gross inefficiency if I am right. A function call has a cost, and image processing is costly before you start.
 
Christian
 
I have several lifelong friends that are New Yorkers but I have always gravitated toward the weirdo's. - Richard Stringer
GeneralRe: TerriblememberGeorgi Petrov30 Mar '05 - 19:17 
This is not the problem, because can be fixed very easy.
Also I have searching for faster code and I found it.
The main problem in convolution is the proper filter selecion, but FFT is still slow for 2.4GHz CPU, so 3x3 5x5 kernels are OK
GeneralRe: TerriblememberChristian Graus31 Mar '05 - 12:03 
Georgi Petrov wrote:
This is not the problem, because can be fixed very easy.
 
No, it can't. You need to fundamentally change how your code works. You need to either use GDI+, or use a DIBSection wrapper to create images in the first place, and you need to work independantly of any device context.
 
Georgi Petrov wrote:
The main problem in convolution is the proper filter selecion
 
That depends. The 'proper' filter won't speed your code up, or make it useful to people wanting to work on images to save them again ( if you load a 24 bit image on an 8 bit display and use this code, you'll generate an 8 bit image to save ).
 
Georgi Petrov wrote:
FFT is still slow for 2.4GHz CPU, so 3x3 5x5 kernels are OK
 
Where did fast fourier transforms enter the discussion ? Or does FFT mean something else here ?
 
No matter what, your code is significantly slower than it could be.

 
Christian
 
I have several lifelong friends that are New Yorkers but I have always gravitated toward the weirdo's. - Richard Stringer
GeneralRe: TerriblememberGeorgi Petrov1 Apr '05 - 1:19 
Yes code is swower, but Fast Fourier Transform for images is swower too. So the image byt reading speed is not so essential if we work with images, but for films you are correct! CGI+ is not very diferernt than CGI, and even more you can take a pointer to bitmap bits direct and to read them without CGI.
 
This code works, and if we need faster code we can go somewere else to search it. CDC* access is very easy to understand. many of real time applications are build to work on a particualr system, so there is not a big problem to use display adpater color values if they are 32bit.
 
And better to make an article where you explayn everything that you know;) This will help you to save your time writing with diferent friends.
 
best

GeneralRe: TerriblememberChristian Graus1 Apr '05 - 8:49 
Georgi Petrov wrote:
Yes code is swower, but Fast Fourier Transform for images is swower too
 
So what ? FFT is slower than what ? It's slower than adding two ints together, for sure. That doesn't mean that when I write a FFT routine ( or any other routine ), that I don't do it properly because it will be slow anyway.
 
Georgi Petrov wrote:
So the image byt reading speed is not so essential if we work with images
 
Bollocks. Given a choice between an app that takes 15 seconds to apply a simple filter, and one that takes 3, which would you choose ?
 
Georgi Petrov wrote:
CGI+ is not very diferernt than CGI
 
Do you mean GDI+ and GDI ? You're ( once again ) sorely mistaken.
 
Georgi Petrov wrote:
even more you can take a pointer to bitmap bits direct and to read them without CGI.
 
You've lost me here.
 
Georgi Petrov wrote:
. CDC* access is very easy to understand
 
Yes - if you sought to write code that was not production value, in order to make the process easier to understand, that's cool. You should have said so.
 
Georgi Petrov wrote:
many of real time applications are build to work on a particualr system
 
Really ? Where ? Windows is designed to hide these specifics so that programmers can code to a universal abstraction. How do you find out how to write code that dodges this and writes direct to the graphics card ?
 
Georgi Petrov wrote:
so there is not a big problem to use display adpater color values if they are 32bit.
 
Well, there's no real difference between 24 and 32 bit displays, but even then, if an image is not 24 bit, it's unacceptable that if an image is saved after a transform, it will be changed in ways the user did not anticipate.
 
Georgi Petrov wrote:
And better to make an article where you explayn everything that you know This will help you to save your time writing with diferent friends.
 
Did you not check for other image processing articles here before writing one ? I've written a series in C# called 'Image Processing for dummies'. The GDI+ code I use easily translates to C++, in fact I wrote it in C++ first and translated it to C#. Smile | :)
 
Christian
 
I have several lifelong friends that are New Yorkers but I have always gravitated toward the weirdo's. - Richard Stringer
GeneralRe: TerriblememberRick York29 Mar '06 - 12:21 
Christian Graus wrote:
Yes - if you sought to write code that was not production value, in order to make the process easier to understand, that's cool. You should have said so.

 
The author did. From the article : "Please note that this article is, by no means, an example of fast processing of pixels. It is merely meant to show how convolution can be done on images."

GeneralRe: TerriblememberChristian Graus29 Mar '06 - 12:23 
I don't recall it saying that before, however.

 
Christian Graus - Microsoft MVP - C++
GeneralRe: TerriblememberFred Ackers30 Mar '06 - 0:22 
You are correct. It did not say that before. I read your post, and thought that you made an important point. So I decided to point out that its not meant for fast processing, its just to show people how to do a simple convolution... And of course to update the solution to VC++.NET 2003 as well.
 
Nothing is impossible, It's merely a matter of finding an answer to the question of HOW? ... And answering that question is usually the most difficult part of the job!!!
 
-- modified at 6:23 Thursday 30th March, 2006
GeneralRe: TerriblememberJKaminski7 Apr '06 - 2:55 
Christian Graus wrote:
Georgi Petrov wrote:
Yes code is swower, but Fast Fourier Transform for images is swower too
 
So what ? FFT is slower than what ? It's slower than adding two ints together, for sure. That doesn't mean that when I write a FFT routine ( or any other routine ), that I don't do it properly because it will be slow anyway.

 
I feel that I need to clarify an obvious misunderstanding here. Georgi Petrov meant that convolution of images can alternatively be done in Fourier domain, by using the FFT to switch between domains. If the filter kernel is larger than - let's say - 7x7, then this method may become acutally faster than doing convolution in spatial domain. But for smaller kernels, the FFT is clearly the bottleneck.
 
Take care,
Juergen
GeneralRe: TerriblememberChristian Graus1 Apr '05 - 8:50 
Hell - I just realised you're not the author, the author has not responded to me at all. Not that I mind, but it changes the perspective of some comments I made.
 
Christian
 
I have several lifelong friends that are New Yorkers but I have always gravitated toward the weirdo's. - Richard Stringer
GeneralRe: TerriblememberMohammad A Gdeisat31 Jul '06 - 9:32 
Hi,
 
I just want to note that discussing such articles does not need to consider heavy optimizations for the source code, plus many of us do not know much about DIBs, so it would be an advantage not mess things up in one article, I can understand convolution right from here, while I can read DIBs from another article, and finally I can write my own optimized code for filtering images.
 
In short, in an article, the author should concentrate on the kernel of the article far away from other details, because the reader reads an article of very specific subject and needs to concentrate on the algorithm itself, not optimizations.
 
Regards,
 
Mohammad Gdeisat
 

 
And ever has it been that love knows not its own depth until the hour of separation

GeneralO! Yes it is excelentmemberGeorgi Petrov26 Aug '04 - 0:45 
You did an excelent work, do you like to join me.
I need someone like you, for open project ECG_1.
It is not ready yet, but I like to expand my(our) work on free open code project for medical records DSP and image DSP too.
So I plane to include some features, like CCD imagin software, and much more DSP capabilities.
http://www.codeproject.com/tools/ecg_dsp.asp

GeneralRe: O! Yes it is excelentmemberChristian Graus30 Mar '05 - 16:04 
Are you going to include DICOM support ?

 
Christian
 
I have several lifelong friends that are New Yorkers but I have always gravitated toward the weirdo's. - Richard Stringer
GeneralRe: O! Yes it is excelentmemberGeorgi Petrov30 Mar '05 - 19:15 
What is DICOM?
Wink | ;)
GeneralRe: O! Yes it is excelentmemberChristian Graus31 Mar '05 - 12:00 
DICOM is THE image format for medical images.
 
Christian
 
I have several lifelong friends that are New Yorkers but I have always gravitated toward the weirdo's. - Richard Stringer
GeneralRe: O! Yes it is excelentmemberwittend22 Oct '07 - 10:02 
DICOM-3 (Digital Image and Communications in Medicine version 3) is not an image format, really. It is a detailed specification concerned with the way image and other binary data is managed and stored in a patient care environment. In addition to bitmap data it contains provisions for the communication and storage of waveform data (i. e. EKG, EEG, sound files) and image sequences (CT, MR, cardiac cine, etc.).
 
DICOM is especially concerned with the meta data (pt. info, study details...) required to make binary information useful as part of a patient care record. It has developed over the last ~25 years from an early desire for interoperability among vendors in radiology and other visually oriented medical specialties. DICOM image management is a nearly universal standard across human and veterinary hospital systems. It began with radiology, and cardiology was one of the first medical specialties to request extension of the standard to accommodate its data needs. DICOM-3 complements other major health care information standards such as HL7.
 
Probably an appropriate subject for an article all by itself... See:
 
http://groups.google.com/group/comp.protocols.dicom/topics?hl=en
 
and:
 
http://dicom.nema.org/
 
among very many others.
GeneralGrayscale conversionsussErik_Egsgard20 Aug '04 - 3:45 
Nice article.Smile | :)
 
But the ratios of R, G and B you are using to convert to grayscale are incorrect. The standard color space for computer graphics is sRGB (for more details see http://www.w3.org/Graphics/Color/sRGB.html).
 
The sRGB ratios for converting to "grayscale" (aka luma) are:
 
gray = 0.2126 * R + 0.701 * G + 0.0722 * B
 

GeneralRe: Grayscale conversionmemberAqiruse20 Aug '04 - 13:58 
According to other documents such as http://www.efg2.com/Lab/ImageProcessing/HistoStretchGrays.htm the numbers I used are correct. These also support the figures I used:
http://www.dfanning.com/ip_tips/color2gray.html
http://www.mathworks.com/access/helpdesk/help/techdoc/creating_plots/chimag15.html
http://www.jasonwaltman.com/thesis/filter-grayscale.html
 
Nothing is impossible, It's merely a matter of finding an answer to the question of HOW? ... And answering that question is usually the most difficult part of the job!!!
GeneralRe: Grayscale conversionsussErik_Egsgard21 Aug '04 - 18:29 
Yes, but all those links are wrong. There is in fact a lot of incorrect information on color science on the internet.
 
To quote from one of those sources: "This "Y" value is the grayscale component in the YIQ color space used in NTSC television"
 
This statement is correct, the equation you are using will produce the grayscale component when dealing with NTSC television. However as I mentioned in my first message, the standard for computer graphics is sRGB.
 
sRGB uses different primaries than NTSC so a different equation to convert to "grayscale" is needed.

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Permalink | Advertise | Privacy | Mobile
Web03 | 2.6.130523.1 | Last Updated 29 Mar 2006
Article Copyright 2004 by Fred Ackers
Everything else Copyright © CodeProject, 1999-2013
Terms of Use
Layout: fixed | fluid