frage12358
frage12358

Reputation: 53

How to use the 'using' command properly?

I just created this account so please forgive me if I forgot some crucial information.

I have the following code but I suspect that there is a memory leak. The goal of the code is to get the bytes from an image from a (simulated) camera und generate an EmguCV image with these. The problem is that the lenght of the generated array never stays the same. When I generate a 300x300 image, I would expect the array to contain 90000 entrys. But that is very rarely the case. The number is constantly changing.

I have tried to follow some tutorials on how to properly use the 'using' command to dispose of the variable but I have failed so far. As far as I can tell there seems to be no IDisposable function for the byte list I am using. So that might be a reason for my failure :/

using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Emgu.CV;
using Emgu.CV.Structure;

namespace opencv_test
{
    class Program
    {
        static void Main(string[] args)
        {
            Stemmer.Cvb.Image image = new Stemmer.Cvb.Image(300, 300);
            image.Initialize(125);
            List<byte> values = new List<byte>();
            CopyPixelWithValue(image, values);

            byte[] myArray = values.ToArray();

            Emgu.CV.Image<Gray, Byte> test = new Image<Gray, Byte>(300, 300);
            test.Bytes = myArray;
            test.Save("D:/abc.jpg");
        }

        static unsafe void CopyPixelWithValue(Stemmer.Cvb.Image toGetValuesFrom, List<byte> values)
        {
            int width = toGetValuesFrom.Width;
            int height = toGetValuesFrom.Height;
            var toCopyData = toGetValuesFrom.Planes[0].GetLinearAccess();

            byte* toCopyBase = (byte*)toCopyData.BasePtr;
            long toCopyYInc = toCopyData.YInc.ToInt64();
            long toCopyXInc = toCopyData.XInc.ToInt64();

            Parallel.For(0, height, y =>
            {
                var pSrcLine = toCopyBase + y * toCopyYInc;

                for (int x = 0; x < width; x++)
                {
                    var srcVal = *(pSrcLine + x * toCopyXInc);
                    values.Add(srcVal);
                }
            });
        }
    }
}

Any help on how to fix this issue would be reatly appreciated!!

Upvotes: 3

Views: 263

Answers (2)

Theodor Zoulias
Theodor Zoulias

Reputation: 43400

You are losing bytes because of unsynchronized multithreaded code inside Parallel.For. Below is an attempt of fixing it.

static void Main(string[] args)
{
    Stemmer.Cvb.Image image = new Stemmer.Cvb.Image(300, 300);
    image.Initialize(125);
    byte[] myArray = GetStemmerImageBytes(image);

    Emgu.CV.Image<Gray, Byte> test = new Image<Gray, Byte>(300, 300);
    test.Bytes = myArray;
    test.Save("D:/abc.jpg");
}

static unsafe byte[] GetStemmerImageBytes(Stemmer.Cvb.Image image)
{
    int width = image.Width;
    int height = image.Height;
    var linearAccess = image.Planes[0].GetLinearAccess();

    byte* sourceBase = (byte*)linearAccess.BasePtr;
    long sourceYInc = linearAccess.YInc.ToInt64();
    long sourceXInc = linearAccess.XInc.ToInt64();

    var result = new byte[width * height];
    Parallel.For(0, height, y =>
    {
        var sourceLine = sourceBase + y * sourceYInc;

        for (int x = 0; x < width; x++)
        {
            var srcVal = *(sourceLine + x * sourceXInc);
            result[y * width + x] = srcVal;
        }
    });
    return result;
}

Upvotes: 0

Eliahu Aaron
Eliahu Aaron

Reputation: 4542

You problem is that you are using a parallel loop to add values to "values" list, you are accessing the same list in multiple threads simultaneously, this is not safe and corrupts the data. Change it to a regular loop and you probably will have no problem.

Upvotes: 3

Related Questions