分类 编程语言 下的文章

参考OpenMPI的文档

Rank可以理解为进程的编号。

CUDA里最基本的线程逻辑结构是顺序的,像一维数组一样,有一个连续递增的线程号(threadIdx.x),且总线程数是线程可知的(blockDim.x)。
MPI也有这两个特性(事实上MPI(1991)要先于CUDA(2007),而我只是恰好先了解的CUDA),不过命名...就没有CUDA那么友好了:使用MPI_Comm_size(...)获取总进程数,通常记为comm_sz这不说谁看得懂啊;使用MPI_Comm_rank获取当前进程编号,通常记为my_rank。这种表记方式来自Peter S. Pacheco的《并行程序设计导论》。

MPI_Init(int *argc, char ***argv)在调用任何MPI函数前调用,类似于初始化的作用

MPI_Send()阻塞性函数,对面不接受就一直阻塞

MPI_Sendrecv(const void *sendbuf, int sendcount, MPI_Datatype sendtype,
    int dest, int sendtag, void *recvbuf, int recvcount,
    MPI_Datatype recvtype, int source, int recvtag,
    MPI_Comm comm, MPI_Status *status)

由于MPI_SendMPI_Recv是阻塞性函数,由于线程竞争或者不恰当的程序逻辑很容易导致死锁,MPI_Sendrecv可以解决这个问题:同时进行发送和接收消息两个动作。

参数依次是: 发送区域起始地址 / 发送数据数量 / 发送数据类型
(向...发送数据的)目标进程编号 / (似乎是)发送的消息编号 / 接收区域起始地址 / 接收数据最大数量
接收数据类型 / (从...接收数据的)源进程编号 / (似乎是)想接收的消息编号
(MPI通讯器?不清楚) / (MPI状态?不清楚

关于Sendrecv这个博客的例子比较简洁易懂。
没仔细看,先丢在这里,关于send/recv tag的:https://stackoverflow.com/questions/31386659/when-to-use-tags-when-sending-and-receiving-messages-in-mpi

MPI_Finalize()(尚不清楚是否一定要求调用)清除进程中所有的MPI状态量,类似于退出MPI环境,在该进程中,之后MPI的函数库中只能调用MPI_Get_version, MPI_Initialized, MPI_Finalized三个函数。

在拿绘制Julia集练手的时候,取参数为-0.8+0.156i的时候,实轴方向有效区域大小约在-2~2之间,而虚轴方向有效区域大小为-1~1。然后用ContourPlot绘制的时候,发现不论xy取值区域大小关系如何,默认都会化画成一个正方形。然后发现自己语文水平8行,不知道该搜什么。。。

想了老半天,试了intervalscale都没有什么效果。不过搜着搜着发现了ratio这一关键词,顺藤摸瓜找到了AspectRatio这一参数。经过试验,该参数至少在ContourPlot内可用。

不过自己画的效果果然还是没有内置函数好,JuliaSetPlot函数和自己根据CUDA编程书设计的Julia函数画起图来效果简直是一个天上一个地下= =

==== 2020/1/8 开题 期末考试终于考!完!了!呼哈哈哈哈哈哈。。哈哈。。哈哈哈。。。(笑岔气.jpg)

然后就到了半年一度的自主项目时间。去年冬天填了一个Java的坑,拿AWT写了个贪吃蛇(不要问,问就是挑战自我),当时下学期要学Java,就正好提前动了一下手;去年夏天因为实验室的工作给机器学习开了个头,看了部分传统方法(线性/Sigmoid函数)的原理,现在稍微想想发现已经忘的差不多了

然后今年冬天的计划还是填坑。去年冬天在RPCS3的Discord里看到有人询问想参与开发该怎么入手,群里Dalao就提到了一个叫CHIP8的东西。然后查了一下,发现是一个非常早期的游戏平台。Dalao说如果是为了入门模拟器的话,可以自由选择一门语言实现它。当时本来是想用Java的,后来想了一下当时编程能力比现在不知道弱到哪里去了虽然现在也蔡的不行,然后正好今年就用C++来实现一下,正好接触一下Qt框架。

UI框架的选择也是看了半天,听说GTK写起来晦涩难懂,wxWidgets可以在修改少量代码的情况下实现跨平台,最后还是选择了庞大的Qt。(光是安装库就用了近2G空间= =)

然后第一坑就是VS2019+Qt插件的配置。 -> Qt + VS2019配置踩坑

唉,没想到今年最后一天竟然在写这个。8说了,过两天还有考试呢。。

  1. 使用glGetUniformLocation获取定义的着色器uniform,输入两个参数:glCreateProgram()返回的标识值,和定义的uniform的名称(string形式)。如果在任一着色器内都没有使用过所定义的uniform的话,GLSL编译器会自动删除该变量,这时返回值是-1,对应unsigned int的值是4294967295。如果使用了错误的programId值也是一样的。

  2. 与着色器相关的函数调用序列如下:
        glCreateProgram()
        glAttachShader()
        glLinkProgram()
        glUseProgram()
        glGetUniformLocation()
        glUniformMatrix4fv()

    来自StackOverflow

最近遇到的场景,有两张图片(cv2的BGR格式)和一个蒙版(只有0,1两种值),需要按照蒙版的值将两张图象合并。

一开始百度咕果上到处查,最接近的大概是bitwise_and函数,但是其起作用的主要是0这个像素值,显然只能实现抠图的功能,但是不能合并。可以看看介个

不废话,看代码:

import numpy as np

def mergeImgs(img1, img2, mask):
    '''
    Replacing places in img1 with img2 where mask = 1.
    '''
    img2 = img2 * mask[:,:,np.newaxis]
    mask = mask * (-1) + 1
    mask = mask.astype('uint8')
    img1 = img1 * mask[:,:,np.newaxis]
    img1 = img1 + img2
    return img1

原理是使用矩阵的乘法运算,把两张图片相反区域的、mask中值为0的区域,像素颜色设置为0,然后再把两张图矩阵相加。由于mask区域是直接用的取反处理,所以不会出现任意一个错误像素点(完美拼图)。

想着想着发现这个+*操作分别对应了OpenCV里的bitwise_andbitwise_or操作,估计最多就是效率上的差别吧= =

总而言之,OpenCV并没有提供一个一步到位的多图区域拼接函数,但是只要思路对了,自己几行代码也能搞定。