0

I'm new to OpenCV and I'm trying to proccess the image from the directory, make it black and white (grayscale) and then write it down to another file. But the output image is quite different from what I expected. Maybe you can help me and indicate the errors in code?

#include <iostream>
#include <opencv2/opencv.hpp>
#include <conio.h>
#include <string.h>
#include <string>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/core/core.hpp>
#include <stdio.h>
#include <stdlib.h>
#include "cuda_runtime.h"
#include "device_launch_parameters.h"

using namespace std;

void faktorial(int InSize, char *DataIn, char *DataOut)// заголовок функции
{
    for(int i = 0,  j = 0; i < InSize; i += 4, j++)
    {
        DataOut[j] = (DataIn[i] + DataIn[i + 1] + DataIn[i + 2]) / 3;
    }

}

int main() 
{        
        char* c = "E:\henrik-evensen-castle-valley-v03.jpg";

        printf("Input source of image\n Example of right directory file: E:\henrik-evensen-castle-valley-v03.jpg\n Your try:\n");
        char *tbLEN;
        tbLEN = new char [1024];

        cin.getline(tbLEN,1024);

        cout << tbLEN;


        IplImage* image;
        image = cvLoadImage(tbLEN, 1);
        int height1 = image->height;
        int width1 = image->width;
        int step = image->widthStep;
        int SizeIn = step*height1;
        char* DatIn = image->imageData;

        IplImage *image2 = cvCreateImage(cvSize(image->width, image->height), IPL_DEPTH_8U, 1);
        char* DatOut = image2->imageData;

        faktorial(SizeIn, DatIn, DatOut);

        cvNamedWindow("Imagecolor");
        cvShowImage("Imagecolor", image);

        cvNamedWindow("Gray");
        cvShowImage("Gray", image2);
        cvWaitKey(0);
        return 0;
}

Input Image Output Image

EDIT: I don't need CvtColor function, I need to use that one factorial function.

Generwp
  • 514
  • 4
  • 16
  • Is there any particular reason you are using the C-API and not the C++ API? You *are* including the C++ headers anyway, and the C-API is as far as I know deprecated. Unless someone is forcing you to, I would recommend not using the C-API. Your error is also likely to disappear if you use the C++ API since it takes care of some things for you. – Hannes Ovrén Apr 20 '16 at 14:57
  • 1
    Possible duplicate of [Convert RGB to Black & White in OpenCV](http://stackoverflow.com/questions/1585535/convert-rgb-to-black-white-in-opencv) – Samer Apr 20 '16 at 15:03
  • **Samer** a lot of thanks for that link, it's quite useful for me, don't know how I could pass that theme. **Hannes Ovrén** So IplImage, cvSaveImage, cvCreateImage, etc are C-API, right? And in my case I need to use Mat, imwrite and others which are from C++ API, am I right? – Generwp Apr 20 '16 at 15:07
  • 1
    Check [this](http://stackoverflow.com/a/34311841/5008845). Just sum up pixels and divide by 3, instead of ORing them. Remember to convert to int before summing pixel up, or you saturate. Also, forget about **obsolete C api**, and use C++ api – Miki Apr 20 '16 at 16:04
  • 1
    as an addition to @Miki's comment take a look at [this page](http://www.johndcook.com/blog/2009/08/24/algorithms-convert-color-grayscale/) – sturkmen Apr 20 '16 at 17:07

3 Answers3

1

Try cvtColor(src, bwsrc, CV_RGB2GRAY); http://docs.opencv.org/2.4/modules/imgproc/doc/miscellaneous_transformations.html (look for cvtColor).

Leonardo Alves Machado
  • 2,747
  • 10
  • 38
  • 53
1

In faktorial you assume you have 3 channels. So you need to increase i by 3, and not by 4. Also, you need to convert char* data to uchar* data, so that accumulation works ok:

You end up with:

void faktorial(int InSize, uchar *DataIn, uchar *DataOut)
{
    for (int i = 0, j = 0; i < InSize; i += 3, j++)
    {
        DataOut[j] = (DataIn[i] + DataIn[i + 1] + DataIn[i + 2]) / 3;
    }
}

You can easily extend this to multiple channels, like:

void faktorial2(int InSize, int nChannels, uchar *DataIn, uchar *DataOut)
{
    for (int i = 0, j = 0; i < InSize; i += nChannels, j++)
    {
        int accum = 0;
        for (int c = 0; c < nChannels; ++c)
        {
            accum += DataIn[i + c];
        }
        DataOut[j] = uchar(accum / nChannels);
    }
}

You in general need also to take image stride into account:

void faktorial3(int rows, int cols, int in_step, int in_channels, int out_step, uchar *in, uchar *out)
{
    for (int r = 0; r < rows; ++r)
    {
        for (int c = 0; c < cols; ++c)
        {
            int accum = 0;
            for (int i = 0; i < in_channels; ++i)
            {
                accum += in[r*in_step + c * in_channels + i];
            }
            out[r*out_step + c] = uchar(accum / in_channels);
        }
    }
}

Here the full code with the calls:

#include <opencv2/opencv.hpp>
using namespace std;

void faktorial3(int rows, int cols, int in_step, int in_channels, int out_step, uchar *in, uchar *out)
{
    for (int r = 0; r < rows; ++r)
    {
        for (int c = 0; c < cols; ++c)
        {
            int accum = 0;
            for (int i = 0; i < in_channels; ++i)
            {
                accum += in[r*in_step + c * in_channels + i];
            }
            out[r*out_step + c] = uchar(accum / in_channels);
        }
    }
}

void faktorial(int InSize, uchar *DataIn, uchar *DataOut)
{
    for (int i = 0, j = 0; i < InSize; i += 3, j++)
    {
        DataOut[j] = (DataIn[i] + DataIn[i + 1] + DataIn[i + 2]) / 3;
    }

}

void faktorial2(int InSize, int nChannels, uchar *DataIn, uchar *DataOut)
{
    for (int i = 0, j = 0; i < InSize; i += nChannels, j++)
    {
        int accum = 0;
        for (int c = 0; c < nChannels; ++c)
        {
            accum += DataIn[i + c];
        }
        DataOut[j] = uchar(accum / nChannels);
    }
}

int main()
{
    char tbLEN[] = "D:\\SO\\img\\barns.jpg";

    IplImage* image;
    image = cvLoadImage(tbLEN, 1);

    IplImage *image2 = cvCreateImage(cvSize(image->width, image->height), IPL_DEPTH_8U, 1);

    int height1 = image->height;
    int width1 = image->width;
    int step = image->widthStep;
    int SizeIn = step*height1;
    int nChannels = image->nChannels;
    uchar* DatIn = (uchar*)image->imageData;
    uchar* DatOut = (uchar*)image2->imageData;

    faktorial(SizeIn, DatIn, DatOut);
    //faktorial2(SizeIn, nChannels, DatIn, DatOut);
    //faktorial3(image->height, image->width, image->widthStep, image->nChannels, image2->widthStep, (uchar*)image->imageData, (uchar*)image2->imageData);

    cvNamedWindow("Imagecolor");
    cvShowImage("Imagecolor", image);

    cvNamedWindow("Gray");
    cvShowImage("Gray", image2);
    cvWaitKey(0);
    return 0;
}

Remember that C api is obsolete. You should switch to C++ api.

Miki
  • 40,887
  • 13
  • 123
  • 202
0

Your faktorial is intended for 4 byte per pixel images (and it doesn't take into account possible line padding).

Loaded from JPG image has 3 byte per pixel, that is why you see 4 shifted ghosts. You can modify faktorial or just convert loaded image to 4-byte format

 image = cvLoadImage(tbLEN, 1);
 cvtColor(image, image, CV_RGB2RGBA); 
MBo
  • 77,366
  • 5
  • 53
  • 86