Lambda拾遗
Lambda拾遗Lambda的状态一般来说, 我们会说当需要保持状态时, 我们会使用函数对象来实现, 这样写很直观. 但是同样可以使用lambda实现某些特别的效果. 例如下面的代码:
12345678910void NormalTester::test_case2(){ int x = 1; auto fun1 = [x]()mutable { TRACE() << "执行结果: " << ++x; }; TRACE() << "执行前: " << TSHOW(x); fun1(); fun1(); fun1(); TRACE() << "执行后: " << TSHOW(x);}
注意, 这里必须要在fun1定义为mutable, 否则编译会不过. 输出为:
12345QDEBUG : NormalTester::test_case2() [ NormalTester: ...
Linux(ubuntu)下Qt6的坑汇集
安装完Qt6之后要注意的事情
Qt installer will notify you to install this two software:
1apt install libxcb-cursor0 libxcb-cursor-dev
其他可能要安装的:sudo apt install libxkbcommon-devsudo apt install libvulkan-dev
cmake说 Qt6_FOUND to FALSE, 但是console程序没问题sudo apt-get install build-essential libgl1-mesa-dev
即使安装工具上面说装了desktop gcc, 照样没用要安装g++。然后就好了也有人说要sudo apt-get install build-essential libgl1-mesa-dev, 貌似没用
Qt6说跑不起来根据它的弹窗的要求,安装那个什么东西,还有人说要安装这个,不过好像不需要了:sudo apt install libxcb-xinerama0
使用国内源.\qt-unified-windo ...
ITK的编译
编译ITKCMAKE配置
下载itk的源码和数据包. 包括源代码和数据文件.
解压缩源码包和数据包, 两个都会被解压缩到同一个目录中. 数据包被解压缩到.ExternalData里面了. 和VTK一样的
创建用于build的itk目录和用于install的目录. 最好将它们分别建立.
运行cmake gui软件, 指定itk的源码目录和build目录, 并指定编译工具为VS2022, 指定编译为x64平台. 再执行配置
寻找CMAKE_INSTALL_PREFIX,这个指定的是ITK的安装根目录, 将其设置为刚才创建的安装目录
选中BUILD_SHARED_LIBS,以编译DLL. 勾选BUILD_EXAMPLES和BUILD_TESTING,我们主要是为了能生成测试数据。按照VTK的经验,必须将这两个都勾上才行(是否如此有待验证)
寻找Module_ITKVtkGlue,并选中它, 然后继续配置. cmake会报错, 找不到Qt的目录
寻找Qt6_DIR, 设置为Qt6的目录, 在我这里安装的是Qt6.6.3,所以,默认的位置在C:/Qt/6.6.3/msvc2019_64/li ...
曲面可视化
本文内容基本上来自于VTKUsersGuid中Visualization Techniques一章的内容的总结, 所有的示例也都改写自VTK的示例. 具体的原代码在哪里记不清楚了, 但是都可以从相关的类的引用中找到.
1. 准备本文会介绍对结构化网格中的某个曲面做可视化的几种技术,这里的例子来自于VTK中的几个例子的简单改写。它使用的是VTK的一个样例数据,combxyz.bin和combq.bin。测试程序界面如下所示:
1.1 数据文件格式和Reader我们使用的文件格式是PLOT3D文件格式,PLOT3D是一个计算机图形程序,用于可视化计算流体动力学的网格,NASA的Overflow CFD软件对PLOT3D格式做了扩展,支持Q变量。它由一个网格文件(也称为XYZ文件,在我们这里就是combxyz.bin文件)和一个可选的解决方案文件(也成为Q文件,在这里就是combq.bin文件)。
VTK提供了vtkMultiBlockPLOT3DReader来提供对它的解析。要做可视化,需要为要做可视化的标量和矢量指定特定的函数号。标量函数有:1 -不读取或计算任何标量100 -密度1 ...
VTK编码笔记
智能指针等
创建对象的智能指针的做法已经改变了。例如, 下面分别是新老代码:1234// 以前的做法:auto renWin = vtkSmartPointer<vtkRenderWindow>::New();// 新的做法:vtkNew<vtkRenderWindow> renWin1;
从文档中描述vtkNew<T>是使用T::New()分配一个对象. 看其源码:
1234567891011template <class T>class vtkNew{ T* Object;public: vtkNew() : Object(T::New()) { vtkNew::CheckTypes(); }}
RTTI
可以使用GetClassName()获取对象类型
IsA()判断类:
if( obj->IsA("vtkExampleClass")){...}
类型转换:SafeDownCase():
vtkExampleCl ...
Day 16 重构扫描生成金字塔图层
我们先重构低倍扫描,为它生成金字塔图层数据。然后同样改造高倍图。
低倍扫描重构思路接下来我们要分析一下如何生成金字塔图层。我们先看高倍扫描的实现,在类HighImageJointer中,我们已经留出了实现的地方。我们看下面的makeTile()函数:
123456789void HighImageJointer::makeTile(int col, int row, cv::Mat image, bool is_last_col, bool is_last_row, bool make_pyrmid){ Q_UNUSED(make_pyrmid) // 暂时不实现金字塔 Q_UNUSED(is_last_row) Q_UNUSED(is_last_col) //TRACE() << "构造tile: " << TSHOW(col) << TSHOW(row); dumpSlice(col, row, image); emit sigDumpSlice(col, row, i ...
Day 15 低倍图区域选择界面
低倍图选区界面我们回过头来继续完善单张扫描的界面。今天我们要处理一下低倍图的选区实现。从功能上讲,低倍图的选区和预览图的选区是很相似的,都是在一个对话框上面拖动一个区域来设置要选择的范围。但是这里要更复杂一些,因为低倍图会扫描几十,上百,甚至上千张——如果使用10倍镜对一张涂满了的玻片做扫描,我们会得到大约1300张照片。当然,一般情况下根本不需要使用这么多,对于一般的样本来说,包含两百个白细胞的外周血区域其实也就大约火柴贵粗细的范围。通常情况下,通过对拍摄得到的预览图的识别处理,只需要拍摄一百左右的低倍图就够了。只有很特殊的情况,比如癌症晚期白细胞特别稀疏,核型,尤其是用户有特别要求才需要扫描整张玻片。
扫描的视野数量多了主要的问题是占用内存资源的大小问题。一张彩色的2448x2048分辨率的照片,图像数据大约会占用15M,1000张照片就是15G内存。对大多数使用环境来说,这是一个很客观的消耗,而且还是一个小概率使用场景。如果是大概率需求,那么事情反而很简单——只要堆资源就行了。反而是小概率事件不好这么做。我们会从易到难,先实现一个支持图像数量适度的实现,然后再考虑如何进一步让它能 ...
string-view, span, range辨析
在某种成都上,string-view,span和range::views在功能上有所相同之处。他们都是对某个连续内存区域的映射,同时并不owner对象。它们的区别主要是在于使用的意图以及功能的多寡上面。
string-view是一个std::string的只读的视图。从某种意义上,我们理解为std::string::c_str的一个面向对象的readonly的封装吧。差不多就是这个意思。
std::span要更通用一些,它不再局限于std::string了。可以只想其他的对象。并且,它即可以是只读的,也可以是读写的。span<T>和span<const T>的区别。另外,在C++23中还有std::mdspan。多维而已,其他的和span在理念上是相通的。
range::views,就更广泛了。但是它的核心思想是lazy evaluation,而且它提供了filter,transform等一票函数,这才是它的重点。
按照我的理解,string-view也好,span也好,应该是传统的指针的替代物,更多的是作为函数的参数使用的,避免数据拷贝的成本;而ra ...
标准库range笔记
以前使用range-v3, C++21中增加了range的支持, 但是感觉差异还是蛮大的. 慢慢收集总结一下.
使用std::range和range-v3的差别使用range-v3,最简单的方式是#include <range/v3/all.hpp>,把所有的头文件都放进去就是了。编译速度慢就慢了,大不了扔到预编译头文件里面去。使用std::range,好像标准库没有给出一个合集,所以需要自己一点点加进去。目前,ranges和algorithm是至少需要的。
range-v3和std::range的对比-views大家都有的:
all
cartesian_product
chunk, chunk_by
concat
counted
common
drop, drop_while
empty
enumerate
filter
iota,range-v3的ints也比较接近
keys, values
join
repeat
reverse
single
split
stride
take, take_while
transform
zip
to
—std::range有的
...
optional,expected,variant做返回值的比较
optional, expected, variant的比较从C++17开始,C++标准中陆续引入了一些表示“替代”意义的数据类型。包括C++17中引入的std::optional,std::variant,以及C++23引入的std::expected。当然,C++17中还引入了std::any,这个和我们讨论的内容距离有点远,就不讨论了。
提到这个问题,是因为在项目中遇到一个设计选择问题,我该如何设计函数的返回值体系,如何让代码看起来更自然易懂,流程更清晰明确。
这里就还牵涉到另一个数据类型,在boost::Leaf,我们会放到一起讨论。
首先看std::optional,它代表一个“可以为空”的值。这里的“空”,从逻辑意义上,表示的是一个没有意义,或者无效的值,最典型的是当表示指针时的空指针。在之前,我们都是使用某个具有特殊意义的值来表示。例如用0表示空指针,用-1表示无效的取值(当合理的值范围为自然数时)等。但是这种方式并不直观,有时也不好用——比如,取值范围为整个有理数区间时,你可能会为找一个“合法的无效值”而头痛。甚至,最简单的,到底是0表示成功还是非0表示成功,就够令人头 ...