Я работаю над проектом, который восстанавливает изображение построчно и должен перекрашивать любые объекты, которые находятся внутри изображения. Наше изображение собирается в режиме реального времени, и мы получаем массив 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]);
}
}
}