PDA

View Full Version : Auto threshold value of monochrome conversion



M. Bashir
26th November 2009, 08:02
Hi All,

It's easy to convert any image to monochrome format by using QImage::convertToFormat like this:

pImage.convertToFormat(QImage::Format_Mono, Qt::MonoOnly|Qt::ThresholdDither|Qt::AvoidDither);
but convertToFormat always guessing that the value of conversion's threshold is 255 where in some cases we need to use another threshold's value. I checked out GIMP and I noticed that it uses an automatic method for guessing threshold's value (see the example below) so I'm wondering:

How I can convert images to monochrome format by using auto threshold's value just like GIMP conversion method?


Original
http://img134.imageshack.us/img134/9741/77363363.th.jpg (http://img134.imageshack.us/i/77363363.jpg/)

QImage conversion
http://img145.imageshack.us/img145/5563/43162085.th.jpg (http://img145.imageshack.us/i/43162085.jpg/)

Automatic GIMP conversion
http://img402.imageshack.us/img402/7148/20634127.th.jpg (http://img402.imageshack.us/i/20634127.jpg/)


P.S

I've wrote a stupid function for converting images to monochrome by using a specified threshold's value as following but I need to know how I can automatically specify threshold's value:

QImage getThresholdBW(QImage pImage, int threshold)
{
QImage result = pImage;
result.fill(255);
for(int x=0; x<pImage.width(); x++)
for(int y=0; y<pImage.height(); y++)
result.setPixel(x, y, qGray(pImage.pixel(x, y))>threshold?qRgb(255, 255, 255):qRgb(0, 0, 0));

return result;
}

wysota
26th November 2009, 09:20
It either uses 127 as the threshold or if it is smarter, it first calculates an average or median of lightness (which is an equivalent of colors->levels->auto) (aka value in HSV) and uses that. Try doing colors->levels->auto on your image and then convert it to monochrome using 127 as the threshold. If it works you can repeat the same process in your application.

M. Bashir
26th November 2009, 10:45
Try doing colors->levels->auto on your image and then convert it to monochrome using 127 as the threshold. If it works
It works.


you can repeat the same process in your application.
I tried to calculate the median but the resultant image isn't correct because the median value is big (about 203)... see my snippet plz:


QImage result = pImage;
QList<int> pixelsValues;
for(int x=0; x<pImage.width();x++)
{
for(int y=0; y<pImage.height();y++)
{
QRgb rgb = pImage.pixel(x,y);
QColor color(rgb);
pixelsValues<<color.lightness();
}
}
qSort(pixelsValues);
int median;
int count = pixelsValues.count();
if(count%2==0)
median = (pixelsValues[count/2]+pixelsValues[(count/2)+1]) / 2;
else
median = pixelsValues[count/2];
threshold = median;
for(int x=0; x<pImage.width(); x++)
for(int y=0; y<pImage.height(); y++)
result.setPixel(x, y, qGray(pImage.pixel(x, y))>threshold?qRgb(255, 255, 255):qRgb(0, 0, 0));
qDebug("threshold = %d", threshold);
return result;

P.S
I'm using Qt 4.6.0 which has lightness function

M. Bashir
26th November 2009, 10:55
You can preview the resultant image down here:

http://img80.imageshack.us/img80/6408/reso.th.png (http://img80.imageshack.us/i/reso.png/)

wysota
26th November 2009, 10:57
Try with an average. Median will tend to make 50% of your pixels white and the other 50% black. If you have one purple spot in a completely yellow picture that's probably not what you would want. Average should do better. If that doesn't help, there is a third choice: (minimum+maximum)/2 - this is exactly what colors->levels->auto should be doing.

M. Bashir
26th November 2009, 12:17
Average should do better
It gave me nearly same result.


there is a third choice: (minimum+maximum)/2 - this is exactly what colors->levels->auto should be doing.
It's working, thanks wysota.


QImage result = pImage;
QList<int> pixelsValues;
for(int x=0; x<pImage.width();x++)
{
for(int y=0; y<pImage.height();y++)
{
QRgb rgb = pImage.pixel(x,y);
QColor color(rgb);
pixelsValues<<color.lightness();
}
}
qSort(pixelsValues);
// int median;
// int count = pixelsValues.count();
// if(count%2==0)
// median = (pixelsValues[count/2]+pixelsValues[(count/2)+1]) / 2;
// else
// median = pixelsValues[count/2];
int median2 = (pixelsValues.first() + pixelsValues.last())/2;
int threshold = median2;
for(int x=0; x<pImage.width(); x++)
for(int y=0; y<pImage.height(); y++)
result.setPixel(x, y, qGray(pImage.pixel(x, y))>threshold?qRgb(255, 255, 255):qRgb(0, 0, 0));
qDebug("threshold = %d", threshold);
// result.save("c:/res.jpg");
return result;