개발 히스토리

c# mat->float[]->하나로 합친후->libtorch

파프리카닷컴 2023. 3. 25. 22:21

먼저 기본적인 float으로 만드는 형태.

using System;
using OpenCvSharp;

public class ImageProcessor 
{
    public float[] LoadImage(string imagePath) 
    {
        // 이미지 파일을 그레이스케일로 불러옵니다.
        Mat image = Cv2.ImRead(imagePath, ImreadModes.GrayScale);

        // 이미지의 높이, 너비, 채널 수를 가져옵니다.
        int height = image.Rows;
        int width = image.Cols;
        int channels = image.Channels();

        // 이미지 데이터를 float 배열로 변환합니다.
        float[] imageData = new float[height * width * channels];
        int idx = 0;
        for (int c = 0; c < channels; c++)
        {
            for (int h = 0; h < height; h++)
            {
                for (int w = 0; w < width; w++)
                {
                    // 0 ~ 255 범위의 값을 0 ~ 1 범위로 정규화합니다.
                    imageData[idx++] = (float)image.At<byte>(h, w, c) / 255.0f;
                }
            }
        }

        // 변환된 이미지 데이터를 반환합니다.
        return imageData;
    }
}

 

 

 

복수개의 float으로 붙이는 코드. 사실상 난 이걸 쓰진 않는다. 

using System;
using System.Linq;
public class ImageProcessor 
{
    public float[] LoadImages(string[] imagePaths) 
    {
        // 이미지 파일들을 불러와서 float 배열로 변환합니다.
        float[][] imageDataList = new float[imagePaths.Length][];
        for (int i = 0; i < imagePaths.Length; i++)
        {
            imageDataList[i] = LoadImage(imagePaths[i]);
        }

        // 이미지 데이터를 하나의 float 배열로 결합합니다.
        float[] imageData = new float[imageDataList.Sum(arr => arr.Length)];
        int offset = 0;
        foreach (float[] arr in imageDataList)
        {
            arr.CopyTo(imageData, offset);
            offset += arr.Length;
        }

        // 변환된 이미지 데이터를 반환합니다.
        return imageData;
    }
}

 

 

 

입력 imageData는 여러 이미지를 연결하여 하나의 float[]으로 만들어진다.

[C, H, W] 차원으로 MAT이 아닌 일반적인 IplImage같은 형태이고, 이걸 멀티 배치로 붙인 것.

이것을 대상으로 libtorch추론하는 코드는 아래와 같다.

#include <torch/torch.h>
void Inference(float* imageData, int batchSize, int channels, int height, int width)
{
  // 이미지당 필요한 메모리 계산. 근데 이거 어디다 쓰노
  int singleImageSize = channels * height * width;
  int totalImageSize = batchSize * singleImageSize;
  // 이미지 데이터를 Tensor 객체로 변환합니다.
  torch::TensorOptions options(torch::kFloat32);
  torch::Tensor tensor = torch::from_blob(imageData, {batchSize, channels, height, width}, options);
  // Tensor 객체를 이용하여 추론을 수행합니다.
 
  // Run the inference on the input tensor
  torch::Tensor output_tensor = module.forward({imageData}).toTensor();

  // Get the predicted classes
  torch::Tensor classes_tensor = torch::argmax(output_tensor, /*dim=*/1);

  // Create a probability map for each class
  torch::Tensor softmax_output_tensor = torch::softmax(output_tensor, /*dim=*/1);
  torch::Tensor probability_map_tensor = softmax_output_tensor.select(/*dim=*/1, /*index=*/1);

  // Convert the probability map to a segmentation mask
  cv::Mat segmentation_mask(batchSize, height, CV_8UC1);

  for (int i = 0; i < batchSize; i++) {
       for (int j = 0; j < height; j++) {
            for (int k = 0; k < width; k++) {
               float probability = probability_map_tensor[i][j][k].item<float>();
                   int class_id = classes_tensor[i][j][k].item<int>();
   				   segmentation_mask.at<uchar>(i, j, k) = (class_id == 1 && probability > 0.5) ? 255 : 0;
   			}
   		}
  }
  cv::imshow("Segmentation Mask", segmentation_mask);
  cv::waitKey(0);
 }

 

 

 

 

 

 

 

 

 

 

CSHAR에서 GPU 메모리 올리는 방법.

문제는...이 구조체를..C++에서 사용할 수 없다는거;;

 

using ManagedCuda;
using ManagedCuda.BasicTypes;
using ManagedCuda.VectorTypes;

public void CopyFloatArrayToGPU(float[] array)
{
    // Initialize CUDA context
    CudaContext cuda = new CudaContext();

    // Allocate memory on the GPU
    CudaDeviceVariable<float> gpuArray = new CudaDeviceVariable<float>(array.Length);

    // Copy the array to the GPU memory
    gpuArray.CopyToDevice(array);

    // Free the allocated memory on the GPU
    gpuArray.Dispose();

    // Dispose of the CUDA context
    cuda.Dispose();
}