2

i had a C++ .exe i was using as a standalone image cleaner. But i now want to use its fonction into my own c# app, so i started to translate it. But i REALLY TOTALLY know nothing about C++ and its logic. So i come here for some help.

First, does anyone know any equivalent for this function? Corona "getPixels()" (yes with an "s" because i know c# have a built-in getPixel) : here is the function explaination from corona doc : getPixels() Corona dll it is used in the lines i am looking to translate.

here is all the thing:

original C++ code:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "corona.h"

#define IMAGE_FORMAT corona::PF_R8G8B8 /* RGB mode - 8 bits each */
#define GetXY(x,y, w)  ((x) + ((w) * (y)))
#define MIN(a, b) ((a) < (b) ? (a) : (b))
#define MAX(a, b) ((a) > (b) ? (a) : (b))

#define SQ(a) ((a) * (a))
#define DISTANCE(a, b, c, d) (SQ(a - c) + SQ(b - d))



int main(int argc, char **argv)
{
corona::Image *img;
unsigned char *pixels;
int threshold = 0;
int distance = 0;
int pixel;
char str[255];
int rows, cols;
int row, col;
unsigned char *bitmap, *p;
unsigned char *outmap;
pixels = (unsigned char*)img->getPixels();
rows = img->getHeight();
cols = img->getWidth();
bitmap = new unsigned char[rows * cols];
p = bitmap;
outmap = new unsigned char[rows * cols];

//convert to single byte grayscale
for (row = 0; row < rows; row++)
for (col = 0; col < cols; col++)
{
    pixel = *pixels++;
    pixel += *pixels++;
    pixel += *pixels++;

    *p++ = pixel / 3;
}

//free corona loading
delete img;

int distance = 8;
int threshold = 7;
//check our threshold
for (row = 0; row < rows; row++)
for (col = 0; col < cols; col++)
{
    if (bitmap[GetXY(col, row, cols)])
    {
        int count = 0;
        int x, y;
        int dhalf = distance / 2 + 1;

        //optimization possible here by checking inside a circle rather than square+dist
        for (x = MAX(col - dhalf, 0); x < MIN(col + dhalf, cols); x++)
        for (y = MAX(row - dhalf, 0); y < MIN(row + dhalf, rows); y++)
        {
            if (SQ(distance) > DISTANCE(col, row, x, y) && bitmap[GetXY(x, y, cols)])
                count++;
        }

        if (count >= threshold)
            outmap[GetXY(col, row, cols)] = 255;
        else
            outmap[GetXY(col, row, cols)] = 0;
    }
    else
        outmap[GetXY(col, row, cols)] = 0;
}
}

What i have now with what i could translate... i hope correctly at least...:

private Bitmap optIm2(Bitmap _img)
        {
            int rows = _img.Height;
            int cols = _img.Width;
            pixels = (unsigned char)img->getPixels();  //here i dont know at all
            bitmap = new unsigned char[rows * cols];  //here i dont know at all
            p = bitmap;
            outmap = new unsigned char[rows * cols];  //here i dont know at all

            //convert to single byte grayscale
            for (int row = 0; row < rows; row++)
            {
                for (int col = 0; col < cols; col++)
                {
                    pixel = *pixels++;  //here i dont know at all
                    pixel += *pixels++;  //here i dont know at all
                    pixel += *pixels++;  //here i dont know at all

                    *p++ = pixel / 3;  //here i dont know at all
                }
            }
            //free corona loading
            delete img;

            int distance = 9;
            int threshold = 7;

            //check our threshold
            for (int row = 0; row < rows; row++)
            {
                for (int col = 0; col < cols; col++)
                {
                    if (bitmap[GetXY(col, row, cols)])
                    {
                        int count = 0;
                        int x, y;
                        int dhalf = distance / 2 + 1;

                        //optimization possible here by checking inside a circle rather than square+dist
                        for (x = Math.Max(col - dhalf, 0); x < Math.Min(col + dhalf, cols); x++)
                        {
                            for (y = Math.Max(row - dhalf, 0); y < Math.Min(row + dhalf, rows); y++)
                            {
                                if (SQ(distance) > DISTANCE(col, row, x, y) && bitmap[GetXY(x, y, cols)])
                                    count++;
                            }
                        }
                        if (count >= threshold)
                        {
                            outmap[GetXY(col, row, cols)] = 255;
                        }
                        else
                        {
                            outmap[GetXY(col, row, cols)] = 0;
                        }
                    }
                    else
                    {
                        outmap[GetXY(col, row, cols)] = 0;
                    }
                }
            }
return iDontKnowWhatYet;
        }


        private int GetXY(int x,int y, int w) { return ((x) + ((w) * (y))); }
        private int SQ(int a) { return ((a) * (a)); }
        private int DISTANCE(int a, int b, int c, int d) { return (SQ(a - c) + SQ(b - d)); }

Could anyone help me understand and convert this please?

user3916429
  • 562
  • 6
  • 25

1 Answers1

3

The C# code will look something like this

private unsafe Bitmap optIm2(Bitmap img)
{
    int rows = img.Height;
    int cols = img.Width;

    var dstImg = new Bitmap(cols, rows, img.PixelFormat);
    var srcImageData = img.LockBits(new Rectangle(0, 0, cols, rows), System.Drawing.Imaging.ImageLockMode.ReadOnly, img.PixelFormat);
    var dstImageData = dstImg.LockBits(new Rectangle(0, 0, cols, rows), System.Drawing.Imaging.ImageLockMode.ReadOnly, dstImg.PixelFormat);
    try
    {
        var bitmap = new byte[rows * cols];
        var outmap = new byte[rows * cols];

        fixed (byte* ptr = &bitmap[0])
        {
            byte* pixels = (byte*)srcImageData.Scan0;
            byte* p = ptr;

            //convert to single byte grayscale
            for (int row = 0; row < rows; row++)
            {
                for (int col = 0; col < cols; col++)
                {
                    var pixel = *pixels++;
                    pixel += *pixels++; 
                    pixel += *pixels++;

                    *p++ = (byte)(pixel / 3);  //here i dont know at all
                }
            }
        }

        int distance = 9;
        int threshold = 7;

        //check our threshold
        for (int row = 0; row < rows; row++)
        {
            for (int col = 0; col < cols; col++)
            {
                if (bitmap[GetXY(col, row, cols)] != 0)
                {
                    int count = 0;
                    int x, y;
                    int dhalf = distance / 2 + 1;

                    //optimization possible here by checking inside a circle rather than square+dist
                    for (x = Math.Max(col - dhalf, 0); x < Math.Min(col + dhalf, cols); x++)
                    {
                        for (y = Math.Max(row - dhalf, 0); y < Math.Min(row + dhalf, rows); y++)
                            if ((SQ(distance) > DISTANCE(col, row, x, y)) && (bitmap[GetXY(x, y, cols)] != 0))
                                count++;
                    }
                    if (count >= threshold)
                        outmap[GetXY(col, row, cols)] = 255;
                    else
                        outmap[GetXY(col, row, cols)] = 0;
                }
                else
                    outmap[GetXY(col, row, cols)] = 0;
            }
        }

        // Copy data from outmap to pixels of bitmap. Since outmap is grayscale data, we replicate it for all channels
        byte* dstPtr = (byte*)dstImageData.Scan0;
        for (int row = 0; row < rows; row++)
        {
            byte* rowPtr = dstPtr;
            for (int col = 0; col < cols; col++)
            {
                *rowPtr++ = outmap[GetXY(col, row, cols)];
                *rowPtr++ = outmap[GetXY(col, row, cols)];
                *rowPtr++ = outmap[GetXY(col, row, cols)];
            }
            dstPtr += dstImageData.Stride;
        }
    }
    finally
    {
        img.UnlockBits(srcImageData);
        img.Dispose();

        dstImg.UnlockBits(dstImageData);
    }

    return dstImg;
}

private int GetXY(int x, int y, int w) { return ((x) + ((w) * (y))); }
private int SQ(int a) { return ((a) * (a)); }
private int DISTANCE(int a, int b, int c, int d) { return (SQ(a - c) + SQ(b - d)); }

While I haven't checked your actual logic for the correct algorithm, the code above contains all the bits you need to do that yourself. The main points to note are:

  1. How to get a pointer from an IntPtr (fixed)
  2. How to get pixel data from a bitmap
  3. How to write pixel data back to a bitmap

Hope this helps!

Ani
  • 10,826
  • 3
  • 27
  • 46
  • @ananthonline First of all thanks a lot for your time. No errors at least, but instead of returning a cleaned image, its returning a yellow rectangle. i am looking into your code to check what is done and why maybe its giving me this. +1 anyway for your time and your really helpful help again – user3916429 Apr 08 '15 at 23:05
  • @ananthonline could you please convert me this last thing? it might fix my problem... `unsigned char *pixels = new unsigned char[width * height * 3]; unsigned char *p = pixels, *b = outmap; int col, row; for (row = 0; row < rows; row++) for (col = 0; col < cols; col++) { *p++ = *b; *p++ = *b; *p++ = *b++; } corona::Image *img = corona::CreateImage(width, height, IMAGE_FORMAT, pixels); corona::SaveImage(filename, corona::FF_AUTODETECT, img);` – user3916429 Apr 08 '15 at 23:55
  • 2
    Updated my answer, hope that's the missing piece! Remember, these are just pointers (pun intended) to give you the tools you need. Now you should have all the bits (I can't stop myself!) needed. – Ani Apr 09 '15 at 00:15
  • well its not doing the job as the original C++ exe was. I guess the only solution for me is to understand EXACTLY what is doing the original C++ code to do the same in C#. For now, your code is giving me a kind of black and white stripped pictures with some noise (maybe some of the "dust" its supposed to clean from the pictures. no idea yet.) i will try to understand all those asterisk thingies that are *loosing **me *so **much xD thanks anyway – user3916429 Apr 09 '15 at 01:01
  • Your description of "striping" sounds like a stride problem. Try using the rowPtr, dstPtr like-approach for the source as well. – Ani Apr 09 '15 at 01:03
  • omg.. that easy to understand http://www.cplusplus.com/doc/tutorial/pointers/, ill keep you int touch after some tries ^^ thanks again – user3916429 Apr 09 '15 at 08:59
  • Understanding now what was doing the C++ code, i totally rewrote it to pure secure C# code, using no pointer at all natives possibilities GetPixel() etc. Well it works pretty fine now... but its damn slow ... i guess pointers a way way faster ... im depressed all of a sudden xD. – user3916429 Apr 09 '15 at 11:45
  • i have been totally unable to fix my problem still... `GetPixel` is the speed problem, so YES `LockBits()` is defintly what is needed. So i was looking again at your code, couldnt understand what you mean on your last comment sadly. I even tried to mix both approach since i know how to deal with array but not memory, tried to create array from bitmap using LockBits... and AccessViolation after only 27lines (y absciss) here: http://codetidy.com/6384/ . So i am totaly lost... If by any luck... you can guide me to the end of this weird thing im trying to do... god... thank you lol – user3916429 Apr 09 '15 at 22:21
  • btw here is what is giving me your code : http://postimg.org/image/gqmvzi3y1/ so it looks like "Dust" (the points, normal i guess), but not the vertical stripes – user3916429 Apr 09 '15 at 22:27
  • And incase it can help you faster, here is the fonction doing what i need exactly in C#; but using the SLOOOWW GetPixel(), so i would kinda need this one with LockBits... At least it might help you get my logic http://codetidy.com/6385/ – user3916429 Apr 09 '15 at 22:33
  • I know where the error comes from! FINALLY, im trying to fix it for now on at least, it looks like the pixels are not RGB but RGBA no idea why... there is gamma ... so the pointers are wrong... – user3916429 Apr 09 '15 at 23:57
  • Great! Now all you need to do is skip the "alpha" pixels (not Gamma) in all the pixel-based loops! :) – Ani Apr 09 '15 at 23:58
  • and another error i found, the `(SQ(distance) > DISTANCE(col, row, x, y)` is always right.... because DISTANCE() return something small under 30 or so, and the second statement is NEVER ==0... i dont understand where it comes from.... – user3916429 Apr 10 '15 at 00:22
  • hmmm its all about `bitmap` ... `bitmap[GetXY(col, row, cols)]` only returns 84 or 85 in the loops... i dont understand but thats it – user3916429 Apr 10 '15 at 00:35
  • Could you upload your source image someplace and give me a link? Since it's my code that doesn't work, I feel obligated to at least have it loop through the pixels correctly. – Ani Apr 13 '15 at 06:00