c# mat->float[]->하나로 합친후->libtorch
먼저 기본적인 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();
}