一、摘要:
本实验使用了opencv Mat类,逐像素访问及修改方法,滚动条及鼠标操作,最终实现了窗宽窗位调节。
二、实验内容:
1. 设计实现一个软件,利用OpenCV一种逐像素访问方法实现图像的窗口窗位调节显示。
2. 基于highgui的鼠标事件实现医学图像的窗口窗位调节。
三、算法流程:
四、代码解析:
实验中首先需要明确何为窗宽窗位。简单的说,正常情况下8位灰度图像素取值为0~255,这也是最普遍使用的图像灰度量化范围;而医学图像灰度范围为0~几千,于是我们需要一个线性映射将一定范围内的源医学图像灰度映射到0~255中。
如下图所示,窗宽可以理解为这个范围的中心,窗宽为这个范围大小。
代码中的实现如下:
show.at<uchar>(i, j) = saturate_cast<uchar>(float(255)/short(width)*(frame.at<short>(i, j)-(level-width/2)));
saturate_cast<uchar>为饱和截断,保证灰度值在0~255。值得注意的是,原图像的像素值范围要远大于255,而将原图像像素映射到8位灰度图的映射为线性映射。该映射的斜率为255/窗宽。如果忽略数字类型转换会导致窗宽大于255时图像全为黑的错误,将斜率转换为float类型可以解决此问题。
此外,设置滚动条事件与鼠标讯息回圈函数代码如下:
void change(int,void*) {
int i = 0;
int j = 0;
for(i=0;i<frame.rows;i++)
for (j = 0; j < frame.cols; j++) {
show.at<uchar>(i, j) = saturate_cast<uchar>(float(255)/short(width)*(frame.at<short>(i, j)-(level-width/2)));
}
}
void mouse(int event, int x, int y, int flags,void* userdata){
switch (event) {
case(2):level = 400; width = 100;;
setTrackbarPos("width", "20374230", width);
setTrackbarPos("level", "20374230", level);
change(0, 0);
break;
}
switch (flags)
{case EVENT_FLAG_LBUTTON:
level= 1500-3*(x - k); width =320-0.5*( y - l);
setTrackbarPos("width", "20374230", width);
setTrackbarPos("level", "20374230", level);
change(0,0);
break;
default:
break;
}
}
鼠标回圈函数利用了滚动条回圈函数。
五、实验过程:
六、实验结果:
实验开始时打开图像如上图显示,初始窗宽设为100,初始窗位设为400。
调节窗宽效果如图显示。
调节窗位效果如图显示。
七、结果分析与实验结论:
本次实验实现了从short型到float型的像素值映射并逐像素访问修改,实现了鼠标事件以及滚动条事件的窗宽窗位调整。实验效果较好。
源码如下:
#include <iostream>
#include<opencv2\opencv.hpp>
using namespace cv;
using namespace std;
Mat k2;
Mat k1;
int level=400;
int width=100;
Mat frame;
Mat show;
int k;
int l;
void change(int,void*) {
int i = 0;
int j = 0;
for(i=0;i<frame.rows;i++)
for (j = 0; j < frame.cols; j++) {
show.at<uchar>(i, j) = saturate_cast<uchar>(float(255)/short(width)*(frame.at<short>(i, j)-(level-width/2)));
}
}
void mouse(int event, int x, int y, int flags,void* userdata){
switch (event) {
case(2):level = 400; width = 100;;
setTrackbarPos("width", "20374230", width);
setTrackbarPos("level", "20374230", level);
change(0, 0);
break;
}
switch (flags)
{case EVENT_FLAG_LBUTTON:
level= 1500-3*(x - k); width =320-0.5*( y - l);
setTrackbarPos("width", "20374230", width);
setTrackbarPos("level", "20374230", level);
change(0,0);
break;
default:
break;
}
}
int main()
{
double n[] = { 1,2,3,4,1,3,4,5,1 };
k1=Mat(3, 3, CV_64FC1, n);
k2 = Mat(3, 3, CV_64FC1,n);
cout << k1 <<endl<<k2 << endl;
cout <<k1*k2<<endl;
cout<<k1.mul(k2)<<endl;
cout << determinant(k1 * k2 - k1.mul(k2));
frame = imread("C:\\Users\\pc\\Desktop\\a736ab2b0ab1e8409780f870fa336e0.png", IMREAD_UNCHANGED);//无更改式读取原图
show = Mat::zeros(frame.rows, frame.cols, CV_8UC1);
namedWindow("20374230");
createTrackbar("width", "20374230", &width, 255 0,change);
createTrackbar("level", "20374230", &level, 2000,change);
setMouseCallback("20374230", mouse);
while (1) {
waitKey(100);
imshow("20374230", show);
}
}
实验用图在此,上传网页后可能格式发生更改了,从而其内部像素值全变成了255。