分类 Python 下的文章

起因是之前闲着没事,自己动手编译了PyTorch和TensorFlow,然后把生成的轮子(.whl)留了下来,打算在之后需要使用的时候自己安装。这里顺便吐槽一句,PyTorch官方的wheel包里自带了cudaRT和CUDNN,搞得安装包动不动上1G(自己编译的非自带版本仅200M+),而且服务器还不稳定,下着下着就自动断线了= =

然后经典安装本地轮子命令:

pip install torch-1.9.0a0+gitdfbd030-cp36-cp36m-win_amd64+cu101.whl

然后直接提示说不支持我装这个包。Python版本是对的,编译和安装wheel时用的也都是64位版本,网上那些Python版本都搞不对的低级错误我怎么可能犯,当时一度怀疑是pip出了问题。试图到网上找pip的verbose选项,结果发现对于pip install指令并不支持这个功能,于是只好回到无头苍蝇状态,继续搜索有关轮子装不上的问题。

然后恰好看到这个提问,里面说pip会使用文件名来判断当前wheel是否支持目标平台。(使用pip debug --verbose可以查看当前平台pip支持的所有目标平台标识符)

然后仔细一想,为了区分CPU和不同CUDA版本下编译出来的轮子,我在每个文件末尾添加了CUDA版本信息,如上面命令中的+cu101,于是猜测是不是这个动作干扰了pip对轮子信息的判定。结果删了之后马上就好了= =

于是得出结论,不要轻易修改python wheel的文件名;如果一定要添加辅助信息的话,可以在版本号后面用加号+链接添加所需要的信息,例如PytTorch自己编译时自动添加的git版本号。

import asyncio, time

async def a(s):
    import time
    await asyncio.sleep(1)
    print(s)

async def b():
    asyncio.ensure_future(a('asd'))
    asyncio.ensure_future(a('qwe'))
    await asyncio.sleep(2)
    print('b')

loop = asyncio.get_event_loop()
B = b()
loop.run_until_complete(B)

要注意的有几个地方:

  1. async def的函数在哪里都可以调用,但是在调用的时候,必须显式等待其结束,否则会出现RuntimeWarning: coroutine 'xxx' was never awaited。在async函数中调用async函数的话,可以使用await关键字直接阻塞等待;在非async函数中则必须设置事件循环器event looper,然后通过事件循环器对所有的异步async函数进行阻塞式等待,避免主线程在子线程完成前退出;
  2. 在协程中休眠线程不能用time.sleep(),而应该用asyncio.sleep(),否则休眠的是整个进程而不是目标协程;
  3. asyncio.ensure_future()比较有意思,提供了类似“用完就扔”的协程运行模式,不必在后续显式await该协程。

相比于用C++写Qt,PyQt更加适合小项目入手,在单文件/单窗口的情况下更容易入手。

静态加载.ui文件需要使用pyuic5进行编译,然后作为库引入,使用一个类去继承该类即可使用。在这个类中,组件可以通过使用ui中指定的objectName直接进行获取,类似于Android中的findViewById

接下来是一些坑:

  1. 组件具有线程绑定性,只能在主线程内更新组件(包括设置组件内容),否则好的情况抛出Exception,坏的情况直接Segmentation Fault退出了,此时只能通过Qt的信号/槽机制来;
  2. 即便是新建QMessageBox也最好在主线程中进行(同样是信号/槽机制),否则可能可以展示信息,但是会出一些奇奇怪怪的错误,我这里遇到的情况就有诸如包含空格就段错误的情景。

最近遇到的场景,有两张图片(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并没有提供一个一步到位的多图区域拼接函数,但是只要思路对了,自己几行代码也能搞定。