图像处理:c++读取.raw图像、c++下旋转和resize处理、c++下梯形畸变校正、c++下更改图像尺寸及pixelSpacing
1. c++读取.raw图像
本人拿到的图像是1024*1024尺寸的,读取该类型图像时,需知图像宽度、高度、像素格式(如8位灰度、16位灰度等)和数据排列方式。
读取代码如:
const int width = 1024;
const int height = 1024;
const std::string file_path = "D://image.raw";
// 1. 读取文件
std::ifstream file(file_path, std::ios::binary | std::ios::ate);
if (!file) {
std::cerr << "文件打开失败!" << std::endl;
return -1;
}
size_t file_size = file.tellg();
file.seekg(0);
std::vector<uint8_t> buffer(file_size);
file.read(reinterpret_cast<char*>(buffer.data()), file_size);
file.close();
// 2. 转换为 16 位像素
std::vector<uint16_t> pixels(width * height);
std::memcpy(pixels.data(), buffer.data(), file_size);
// 3. 转换为 OpenCV 图像并显示
cv::Mat image(height, width, CV_16UC1, pixels.data());
//取反
cv::Mat image_inverse(image.cols, image.cols, CV_16UC1);
for (int i = 0; i < image.cols; i++)
{
for (int j = 0; j < image.cols; j++)
{
image_inverse.at<ushort>(i, j) = 65535 - image.at<ushort>(i, j);
}
}
cv::imshow("Image", image_inverse);
cv::waitKey(0);
2. c++下旋转和resize处理
以上读取的图像存在旋转角度,并且尺寸太大,需要对图像进行旋转和resize处理。
处理代码如下:
//旋转90°
cv::Mat image_inverse_rotate;
cv::transpose(image_inverse, image_inverse_rotate);
cv::flip(image_inverse_rotate, image_inverse_rotate, 0);
//resize为512*512
cv::Mat image_inverse_rotate_resize;
cv::resize(image_inverse_rotate, image_inverse_rotate_resize, cv::Size(512, 512));
cv::imshow("Image", image_inverse_rotate_resize);
cv::waitKey(0);
3. c++下梯形畸变校正
以上获取到的图像存在一定的畸变(梯形畸变),需要对其进行校正,通过同时调整四个点,将图像从一种视角变换到另一种视角。主要有三个步骤:
a、定义源点和目标点:
-----源点是原始图像的四个角点。
-----目标点是变换后图像的四个角点。
b、计算变换矩阵:
-----根据源点和目标点计算透视变换矩阵。
c、应用变换:
-----将变换矩阵应用到原始图像上,得到校正后的图像,然后再根据自己想要的尺寸进行裁剪。
代码如下:
// 定义梯形区域的四个角点(假设已知)
std::vector<cv::Point2f> srcPoints;
srcPoints.push_back(cv::Point2f(50, 78)); // 左上角
srcPoints.push_back(cv::Point2f(400, 78)); // 右上角
srcPoints.push_back(cv::Point2f(404, 234)); // 右下角
srcPoints.push_back(cv::Point2f(30, 234)); // 左下角
// 定义校正后的矩形区域的四个角点
std::vector<cv::Point2f> dstPoints;
dstPoints.push_back(cv::Point2f(30, 78)); // 左上角
dstPoints.push_back(cv::Point2f(404,78)); // 右上角
dstPoints.push_back(cv::Point2f(404, 234)); // 右下角
dstPoints.push_back(cv::Point2f(30, 234)); // 左下角
// 计算透视变换矩阵
cv::Mat perspectiveMatrix = cv::getPerspectiveTransform(srcPoints, dstPoints);
// 应用透视变换
cv::Mat dst;
cv::warpPerspective(src, dst, perspectiveMatrix, cv::Size(414, 313));
// 显示结果
cv::imshow("Source Image", src);
cv::waitKey(0);
cv::imshow("Corrected Image", dst);
cv::waitKey(0);
4. c++下更改图像尺寸及pixelSpacing
为了满足需求,需要更改图像尺寸和像素分辨率,原图像的分辨率伟0.308,要求转为0.4
代码如下:
//进行pixel的修改
double original_spacing = 0.308;
double target_spacing = 0.4;
int new_width = static_cast<int>(Dstimage.rows * target_spacing / original_spacing);
int new_height = new_width;
// 使用双线性插值放大图像
Mat resized_img_newResoltion;
cv::resize(Dstimage, resized_img_newResoltion, cv::Size(new_width, new_height), 0, 0, cv::INTER_LINEAR);
附:
关键概念(例)
–1.像素分辨率:
----a.0.976单位/像素:表示每个像素的物理尺寸伟0.976×0.976单位(如mm)
----b.0.5单位/像素:表示目标分辨率下,每个像素的物理尺寸更小(图像更“密集”)
–2.物理尺寸与像素尺寸的关系:
----a.原始物理尺寸:28 × 0.976 = 27.328 单位。
----b.目标物理尺寸:28 × 0.5 = 14.0 单位。
----c.矛盾点:如果保持 28×28 像素不变,物理尺寸会缩小(从 27.328 → 14.0 单位),这本质上是 提高了图像的分辨率密度(单位距离内像素更多)
若目标是保持物理内容不变 但 修改分辨率标签(不实际插值像素),只需更新图像的元数据(如 DICOM 中的 Pixel Spacing 字段)。
若需 物理内容适配新分辨率,则需要通过插值调整图像尺寸(但会改变像素矩阵大小)。
方法 1:仅修改分辨率标签(不改变像素数据)
代码如下:
// 假设原始图像是 28x28,分辨率为 0.976
cv::Mat image = cv::Mat::zeros(28, 28, CV_8UC1); // 示例图像
// 修改分辨率标签(OpenCV 本身不存储分辨率,需借助其他库如 DCMTK)
double new_spacing = 0.5; // 目标分辨率
// 通常需要保存为 DICOM 或自定义格式时更新元数据
std::cout << "修改后的分辨率: " << new_spacing << " unit/pixel" << std::endl;
return 0;
方法 2:通过插值调整物理内容(改变像素矩阵)
如果目标是 保持物理尺寸 27.328 单位 但 分辨率改为 0.5 单位/像素,则需重新计算像素矩阵大小:
计算目标像素尺寸:
新宽度 = 原始物理宽度 / 新分辨率 = 27.328 / 0.5 ≈ 55 像素
新高度 = 原始物理高度 / 新分辨率 = 27.328 / 0.5 ≈ 55 像素
使用 resize() 插值放大图像到 55×55 像素。
代码如下:
cv::Mat src = cv::Mat::zeros(28, 28, CV_8UC1); // 示例图像
//计算新尺寸(保持物理尺寸不变)
double original_spacing = 0.976;
double target_spacing = 0.5;
int new_width = static_cast<int>(28 * original_spacing / target_spacing); // ≈55
int new_height = new_width;
// 使用双线性插值放大图像
cv::Mat dst;
cv::resize(src, dst, cv::Size(new_width, new_height), 0, 0, cv::INTER_LINEAR);
std::cout << "新图像尺寸: " << dst.size() << std::endl;
return 0;