Editing images using OpenCV without ready functions

3

I have the following image shown below and I need to turn it gray and then binarize it.

Iusethefollowingcodetoshowitonthescreen

cv::Matimg=cv::imread("lena.jpg");// Lê a imagem no local onde ela é gerada(matriz)
cv::namedWindow("RGB");
cv::imshow("RGB",img); //abre a imagem na janela do windows de nome olá mundo
int keyCode = cvWaitKey( ); // Manter janela ativa equanto nenhuma tecla for pressionada

return 1;

But I need to turn this image to gray without using ready-made functions like cvCvtColor or cvThreshold, could anyone help me by indicating at least one article that deals with the subject?

    
asked by anonymous 24.08.2015 / 23:41

1 answer

7

To do what you need, simply scroll through the pixels of the image using the Mat::at . This function allows you to access the value of a pixel in a given coordinate x and y .

Conversion to Ash

Conversion to shades of gray can be done in a few different ways. The simplest way is with the average method: you basically average the values in each color band (red, green and blue) to get a single luminous intensity value. A slightly better method is the extraction of brightness. In this method, you average only of the highest and lowest values of those bands (thus ignoring that intermediate color). Finally, another method is directly related to how humans perceive the world. The proportions used in this formula are derived from the proportions of the cones (photosensitive cells in the human retina):

Theaveragemethodispracticallythesameasthebrightnessmethod,andtheytendtoreducethecontrast.Thebrightnessmethodworksbestoverall,somuchsothatitisthemostcommonlyusedmethod(includingeditingtoolssuchasGimporPhotoshop).Anotherreasonforittobeusedisthathumansaremoresensitivetogreen,andsothisformofconversionusuallygeneratesimagesthataremorepleasingtohumanperception.

BinaryImage

Onthresholding,theprocessusedtocreateabinaryimage,thisisanequallysimpleprocess.Simplyprocessallthepixelsandchangethemto0(theequivalentofblack)or255(theequivalentofwhite)dependingonwhethertheyareaboveorbelowachosenthreshold.Thechoiceofhowtodothisisaconvention,butitusuallyturnsinto0ifthevalueislessthanorequalandtransformto255ifitisgreaterthanthethreshold.Choosingthethresholdisbasedonwhatyouwanttodo(forexample,separatingobjectsfromthebackground)andalsothecolordistributionintheimage(usethe color histogram to do this analysis).

Examples

Here is a sample code that does what is explained:

#include <opencv2/highgui/highgui.hpp>

using namespace cv;

// Método da Média: Média dos valores das cores
uchar metodoMedia(Vec3b RGB)
{
    uchar azul = RGB.val[0];
    uchar verde = RGB.val[1];
    uchar vermelho = RGB.val[2];

    return (uchar) ((azul + verde + vermelho) / 3);
}

// Método do Brilho: Média dos valores máximos e mínimos das cores
uchar metodoBrilho(Vec3b RGB)
{
    uchar azul = RGB.val[0];
    uchar verde = RGB.val[1];
    uchar vermelho = RGB.val[2];

    return (uchar) ((std::max(std::max(azul, verde), vermelho) + std::min(std::min(azul, verde), vermelho)) / 2);
}

// Método da Luminosidade: Ponderação decorrente das proporções médias de cones no olho humano
uchar metodoLuminosidade(Vec3b RGB)
{
    uchar azul = RGB.val[0];
    uchar verde = RGB.val[1];
    uchar vermelho = RGB.val[2];

    return (uchar) ((0.21 * vermelho) + (0.72 * verde) + (0.07 * azul));
}

int main()
{
    // --------------------------------------------
    // Carrega a imagem original
    // --------------------------------------------

    Mat img = imread("lena.jpg"); // A imagem RGB carregada é CV_8UC3 porque tem três canais, as cores (R + G + B).

    int largura = img.size().width;
    int altura = img.size().height;

    // --------------------------------------------
    // Cria uma nova imagem em tons de cinza
    // (com o método de luminosidade)
    // --------------------------------------------

    Mat gray(largura, altura, CV_8UC1); // A nova imagem criada só tem 1 canal (CV_8UC1), a intensidade luminosa.

    int x, y;
    for(x = 0; x < largura; x++)
    {
        for(y = 0; y < altura; y++)
        {
            Vec3b pixel = img.at<Vec3b>(x, y);
            uchar intensidade = metodoLuminosidade(pixel);
            gray.at<uchar>(x, y) = intensidade;
        }
    }

    // --------------------------------------------
    // Cria uma imagem binarizada
    // --------------------------------------------

    Mat bin(largura, altura, CV_8UC1); // Essa imagem também só tem 1 canal, de preto e branco.
    uchar limiar = 128; // Limiar utilizado.

    // O método é o seguinte:
    // Pixels com luminosidade abaixo do limiar se tornam "preto" (0), e acima se tornam "branco" (255).
    for(x = 0; x < largura; x++)
    {
        for(y = 0; y < altura; y++)
        {
            Vec3b pixel = img.at<Vec3b>(x, y);
            uchar intensidade = metodoLuminosidade(pixel);

            if(intensidade <= limiar)
                bin.at<uchar>(x, y) = 0;
            else
                bin.at<uchar>(x, y) = 255;
        }
    }

    namedWindow("Imagem Original");
    imshow("Imagem Original",img);

    namedWindow("Imagem em Cinza");
    imshow("Imagem em Cinza", gray);

    namedWindow("Imagem Binária");
    imshow("Imagem Binária", bin);

    cvWaitKey();

    return 0;
}

The result of this code is the following windows:

Althoughthemethodofluminosity(thatderivedfromhumanperception)isthemostused,itisnoticedthattheothermethodsgenerateverysimilarresults.Seetheexamplesbelow(Ididnotputthecodethatgeneratestheseimages,butjustusethethreemethodsthatexistinthepreviouscode):

It should be possible to note that the last image is darker (it has a higher mean luminous intensity) and also more beautiful (although this is a matter of opinion). This is due to the fact that greenness is given more weight in the method of luminosity, as it happens in human perception. Still, there may be some use where the other methods are interesting (when you just want to reduce the contrast between light and dark in the image).

  

IMPORTANT: Note in the code (especially in the conversion functions   for the various methods) that although I (and you) call the pattern   three RGB bands (because of Red, Green and Blue), OpenCV uses BGR   in the manipulation of your images!

    
31.08.2015 / 23:17