Обработка изображения: указатель становится нулевым без сброса - PullRequest
0 голосов
/ 07 июня 2019

Я работаю над проектом, который восстанавливает изображение построчно и должен перекрашивать любые объекты, которые находятся внутри изображения. Наше изображение собирается в режиме реального времени, и мы получаем массив 1D byte[] при каждом вызове. Помещение каждого 1D массива друг на друга восстанавливает 2D изображение. Эта программа имеет буфер из 300 массивов, который достаточно велик для отображения каждого объекта.

Данные внутри массива представляют собой числовое значение, соответствующее цвету. Объекты часто имеют несколько цветов, и этот код должен перекрасить каждый объект в самый современный цвет.

Первоначально этот код был написан на C #, но у меня было несколько проблем с производительностью, поэтому эта программа была адаптирована к проекту CLI / CLR с C ++, чтобы иметь доступ к указателям, которые значительно повысили бы скорость.

Для каждого пикселя в массиве я создаю класс Product , который содержит данные о текущем пикселе. Каждый класс Product содержит указатель на класс Info , содержащий данные о текущем объекте. Программа просматривает предыдущие соседние пиксели и определяет, принадлежит ли пиксель к тому же объекту. Если это так, указатель Info в классе Product текущего пикселя будет указывать на класс Info предыдущего пикселя. Таким образом, при подсчете каждого цвета всего объекта мне нужно только обновить самый существующий индекс цвета в классе Info , чтобы обновить цвет каждого пикселя и, таким образом, перекрасить весь объект.

Вот основной код с циклом:

    void ProductsClipping::ProcessClippingFrame(array<unsigned char>^% CurrentProcessingFrame) {
        Monitor::Enter(obj);
        try {
            // Update Current Buffer Index
            BufferIndex++;
            if (BufferIndex >= BufferSize) BufferIndex = 0;

            // Get Current Frame
            CurrentProductFrame = ProductResult[BufferIndex];

            // Update Result Buffer Index
            ResultBufferIndex++;
            if (ResultBufferIndex >= BufferSize) ResultBufferIndex = 0;

            // Get Result Frame
            ResultFrame = ProductResult[ResultBufferIndex];

            // Process each pixel
            for (int i = 0; i < PixelsCount; i++) {
                Product^ LastProduct = LastProductFrame[i];

                if (LastProduct != nullptr && LastProduct->ProductInfo != nullptr && LastProduct->ProductInfo->BufferIndex != BufferIndex) {
                    LastProduct->ProductInfo->Height++;
                    LastProduct->ProductInfo->BufferIndex = BufferIndex;
                    LastProduct->ProductInfo->isResetMax = true;
                    LastProduct->ProductInfo->isActive = false;
                    LastProduct->UpdateProductIndex();
                }

                // If product in this pixel 
                if (CurrentProcessingFrame[i] > 0) {
                    bool hasParent = false;

                    // If last pixel don't belong to this product
                    if (CurrentProductFrame[i] == nullptr) CurrentProductFrame[i] = gcnew Product;
                    Product^ CurrentProduct = CurrentProductFrame[i];

                    // Check if has a particle in above pixel
                    if (LastProduct != nullptr && LastProduct->ProductID > 0) {
                        CurrentProduct->Update_Info(LastProduct->ProductInfo, LastProduct->ProductID, false);
                        hasParent = true;
                    }
                    Product^ PreviousProduct = i > 0 ? CurrentProductFrame[i - 1] : nullptr;

                    // Check if is a particle in the left of the pixel
                    if (PreviousProduct != nullptr && PreviousProduct->ProductID > 0) {
                        // If has particle above and in the left of pixel and the two particle is not the same
                        if (hasParent) {
                            if (PreviousProduct->ProductID != CurrentProduct->ProductID) {
                                PreviousProduct->Update_Info(CurrentProduct->ProductInfo, CurrentProduct->ProductID, true);
                            }
                        } else {
                            CurrentProduct->Update_Info(PreviousProduct->ProductInfo, PreviousProduct->ProductID, false);
                            hasParent = true;
                        }
                    }

                    if (!hasParent) {
                        if (i + 1 < CurrentProcessingFrame->Length && CurrentProcessingFrame[i + 1] > 0) {
                            CurrentProductFrame[i + 1] = CurrentProduct;

                            // End of product
                            if (LastProduct != nullptr && LastProduct->IsEndOfProduct && i == LastProduct->ProductInfo->LastMax) {
                                LastProduct->Close();
                            }
                            continue;
                        } else {
                            CurrentProduct->ProductID = ProductID;
                            ProductID++;
                        }
                    }

                    // If first pixel of product. Initialize information data
                    if (CurrentProduct->ProductInfo == nullptr) {
                        CurrentProduct->Initialize_Info(gcnew Info());
                        CurrentProduct->ProductInfo->ID = CurrentProduct->ProductID;
                        CurrentProduct->ProductInfo->BufferIndex = BufferIndex;
                    }
                    CurrentProduct->ProductInfo->LastMax = (CurrentProduct->ProductInfo->isResetMax) ? i : Math::Max(i, CurrentProduct->ProductInfo->LastMax);
                }

                // If End of product
                if (LastProduct != nullptr && LastProduct->IsEndOfProduct && i == LastProduct->ProductInfo->LastMax) LastProduct->Close();
                ResultFrame[i] = nullptr;
            }
            LastProductFrame = CurrentProductFrame;
        } finally { Monitor::Exit(obj); }
    }

Это код класса Product с указателем Info .

ref class Product {
    private:
        Info^ *_ProductInfo = nullptr;

    public:
        unsigned int ProductID;
        property Info^ ProductInfo {
            Info^ get() {
                if (!_ProductInfo) return nullptr;
                return *_ProductInfo;
            }
        }

        property bool IsEndOfProduct {
            bool get() { return ProductInfo != nullptr && ProductInfo->isOpen && !ProductInfo->isActive; }
        }

        void Update_Info(Info^ NewInfo, unsigned int NewProductID, bool isBelongOtherProduct) {
            if (NewInfo != nullptr) NewInfo->isActive = true;
            ProductID = NewProductID;
            _ProductInfo = &NewInfo;
        }

        void Initialize_Info(Info^ NewInfo) {
            _ProductInfo = &NewInfo;
        }

        void Close() {
            ProductInfo->isOpen = false;
        }
};

Проблема, с которой я сталкиваюсь, заключается в том, что для первого пикселя в объекте указатель правильно указывает на класс Info , но на следующей итерации, когда требуется установить следующий пиксель на тот же Info class, первый указатель становится nullptr

РЕДАКТИРОВАТЬ: Добавлен тестовый код вызова цикла:

public partial class Form1 : Form
{
    byte[][] Frame = new byte[][]
    {
                new byte[]{ 0, 0, 1, 0, 0, 0, 1, 0, 0, 0 },
                new byte[]{ 0, 1, 1, 0, 0, 1, 1, 0, 0, 0 },
                new byte[]{ 0, 1, 1, 1, 1, 1, 1, 1, 0, 0 },
                new byte[]{ 0, 0, 1, 1, 1, 1, 0, 1, 0, 0 },
                new byte[]{ 0, 0, 0, 1, 0, 1, 0, 1, 0, 0 },
                new byte[]{ 0, 0, 1, 0, 0, 1, 1, 1, 0, 0 },
                new byte[]{ 0, 0, 1, 1, 1, 1, 1, 0, 0, 0 },
                new byte[]{ 0, 0, 0, 0, 0, 0, 1, 1, 0, 0 },
                new byte[]{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
                new byte[]{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
                new byte[]{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
                new byte[]{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
    };

    ProductsClipping ClippingFrame;

    public Form1()
    {
        InitializeComponent();

        int NbArrays = Frame.Length;

        for (int i = 0; i < NbArrays; i++)
        {
            ClippingFrame.ProcessClippingFrame(ref Frame[i]);
        }
    }
}
...