-
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();
}