Begone的文章

  • OpenCV+特征检测

    Harris Corner Detection检测函数cv.cornerHarris()。其参数为:

    img 输入图像,应为灰度和float32类型
    blockSize是拐角检测考虑的邻域大小
    ksize 使用的Sobel导数的光圈参数
    k 等式中的哈里斯检测器自由参数

    import numpy as npimport cv2 as cvfilename = 'chessboard.png'img = cv.imread(filename)gray = cv.cvtColor(img,cv.COLOR_BGR2GRAY)gray = np.float32(gray)dst = cv.cornerHarris(gray,2,3,0.04)#result用于标记角点,并不重要dst = cv.dilate(dst,None)#最佳值的阈值,它可能因图像而异。img[dst>0.01*dst.max()]=[0,0,255]cv.imshow('dst',img)if cv.waitKey(0) & 0xff == 27:cv.destroyAllWindows()
    SubPixel精度的转角函数cv.cornerSubPix(),它进一步细化了以亚像素精度检测到的角落。和往常一样,我们需要先找到哈里斯角。
    然后我们通过这些角的质心(可能在一个角上有一堆像素,我们取它们的质心)来细化它们。对于这个函数,我们必须定义何时停止迭代的条件。我们在特定的迭代次数或达到一定的精度后停止它,无论先发生什么。我们还需要定义它将搜索角落的邻居的大小。
    import numpy as npimport cv2 as cvfilename = 'chessboard2.jpg'img = cv.imread(filename)gray = cv.cvtColor(img,cv.COLOR_BGR2GRAY)寻找哈里斯角gray = np.float32(gray)dst = cv.cornerHarris(gray,2,3,0.04)dst = cv.dilate(dst,None)ret, dst = cv.threshold(dst,0.01*dst.max(),255,0)dst = np.uint8(dst)# 寻找质心ret, labels, stats, centroids = cv.connectedComponentsWithStats(dst)# 定义停止和完善拐角的条件criteria = (cv.TERM_CRITERIA_EPS + cv.TERM_CRITERIA_MAX_ITER, 100, 0.001)corners = cv.cornerSubPix(gray,np.float32(centroids),(5,5),(-1,-1),criteria)# 绘制res = np.hstack((centroids,corners))res = np.int0(res)img[res[:,1],res[:,0]]=[0,0,255]img[res[:,3],res[:,2]] = [0,255,0]cv.imwrite('subpixel5.png',img)
    Shi-tomas拐角检测器和益于跟踪的特征它通过Shi-Tomasi方法(或哈里斯角检测,如果指定)找到图像中的N个最强角。像往常一样,图像应该是灰度图像。然后,指定要查找的角数。然后,您指定质量级别,该值是介于0-1 之间的值,该值表示每个角落都被拒绝的最低拐角质量。然后,我们提供检测到的角之间的最小欧式距离。 利用所有这些信息,该功能可以找到图像中的拐角。低于平均质量的所有拐角点均被拒绝。然后,它会根据质量以降序对剩余的角进行排序。然后函数首先获取最佳拐角,然后丢弃最小距离范围内的所有附近拐角,然后返回N个最佳拐角。 在下面的示例中,我们将尝试找到25个最佳弯角:
    import numpy as npimport cv2 as cvfrom matplotlib import pyplot as pltimg = cv.imread('blox.jpg')gray = cv.cvtColor(img,cv.COLOR_BGR2GRAY)corners = cv.goodFeaturesToTrack(gray,25,0.01,10)corners = np.int0(corners)for i in corners:x,y = i.ravel()cv.circle(img,(x,y),3,255,-1)plt.imshow(img),plt.show()
    SIFT尺度不变特征变换import numpy as npimport cv2 as cvimg = cv.imread('home.jpg')gray= cv.cvtColor(img,cv.COLOR_BGR2GRAY)sift = cv.xfeatures2d.SIFT_create()kp = sift.detect(gray,None)#sift.detect()函数在图像中找到关键点。如果只想搜索图像的一部分,则可以通过掩码。每个关键点是一个特殊的结构,具有许多属性,例如其(x,y)坐标,有意义的邻域的大小,指定其方向的角度,指定关键点强度的响应等。img=cv.drawKeypoints(gray,kp,img)#OpenCV还提供**cv.drawKeyPoints**()函数,该函数在关键点的位置绘制小圆圈。 如果将标志**cv.DRAW_MATCHES_FLAGS_DRAW_RICH_KEYPOINTS**传递给它,它将绘制一个具有关键点大小的圆,甚至会显示其方向。cv.imwrite('sift_keypoints.jpg',img)
    SURF简介(加速)SURF.detect(),SURF.compute()等来查找关键点和描述符。
    # 创建SURF对象。你可以在此处或以后指定参数# 这里设置海森矩阵的阈值为400,在实际情况下,最好将值设为300-500surf = cv.xfeatures2d.SURF_create(400)# 直接查找关键点和描述符 kp, des = surf.detectAndCompute(img,None)
    用于角点检测的FAST算法(任何其他特征检测器)可以指定阈值,是否要应用非极大抑制,要使用的邻域等。 对于邻域,定义了三个标志,分别为cv.FASTFEATURE_DETECTOR_TYPE_5\-8 , cv.FASTFEATURE_DETECTOR_TYPE_7\-12 和cv.FASTFEATURE_DETECTOR_TYPE_9\-16 。
    import numpy as npimport cv2 as cvfrom matplotlib import pyplot as pltimg = cv.imread('simple.jpg',0)# 用默认值初始化FAST对象fast = cv.FastFeatureDetector_create()# 寻找并绘制关键点kp = fast.detect(img,None)img2 = cv.drawKeypoints(img, kp, None, color=(255,0,0))# 打印所有默认参数print( "Threshold: {}".format(fast.getThreshold()) )print( "nonmaxSuppression:{}".format(fast.getNonmaxSuppression()) )print( "neighborhood: {}".format(fast.getType()) )print( "Total Keypoints with nonmaxSuppression: {}".format(len(kp)) )cv.imwrite('fast_true.png',img2)# 关闭非极大抑制(一个位置只有一个关键点)fast.setNonmaxSuppression(0)kp = fast.detect(img,None)print( "Total Keypoints without nonmaxSuppression: {}".format(len(kp)) )img3 = cv.drawKeypoints(img, kp, None, color=(255,0,0))cv.imwrite('fast_false.png',img3)
    BRIEF(二进制的鲁棒独立基本特征)它提供了一种直接查找二进制字符串而无需查找描述符的快捷方式。它需要平滑的图像补丁,并以独特的方式(在纸上展示)选择一组n_d(x,y)位置对。然后,在这些位置对上进行一些像素强度比较。例如,令第一位置对为p和q。如果I(p)<I(q),则结果为1,否则为0。将其应用于所有n_d个位置对以获得n_d维位串。
    BRIEF是特征描述符,它不提供任何查找特征的方法。函数brief.getDescriptorSize() 给出以字节为单位的n_d大小。默认情况下为32。
    import numpy as npimport cv2 as cvfrom matplotlib import pyplot as pltimg = cv.imread('simple.jpg',0)# 初始化FAST检测器star = cv.xfeatures2d.StarDetector_create()# 初始化BRIEF提取器brief = cv.xfeatures2d.BriefDescriptorExtractor_create()# 找到STAR的关键点kp = star.detect(img,None)# 计算BRIEF的描述符kp, des = brief.compute(img, kp)print( brief.descriptorSize() )print( des.shape )
    ORB(面向快速和旋转的BRIEF)与往常一样,我们必须使用函数cv.ORB()或使用feature2d通用接口来创建ORB对象。它具有许多可选参数。最有用的是nFeatures,它表示要保留的最大特征数(默认为500),scoreType表示是对特征进行排名的Harris分数还是FAST分数(默认为Harris分数)等。另一个参数WTA_K决定点数产生定向的BRIEF描述符的每个元素。默认情况下为两个,即一次选择两个点。在这种情况下,为了匹配,将使用NORM_HAMMING距离。如果WTA_K为3或4,则需要3或4个点来生成Brief描述符,则匹配距离由NORM_HAMMING2定义。 下面是显示ORB用法的简单代码。
    import numpy as npimport cv2 as cvfrom matplotlib import pyplot as pltimg = cv.imread('simple.jpg',0)# 初始化ORB检测器orb = cv.ORB_create()# 用ORB寻找关键点kp = orb.detect(img,None)# 用ORB计算描述符kp, des = orb.compute(img, kp)# 仅绘制关键点的位置,而不绘制大小和方向img2 = cv.drawKeypoints(img, kp, None, color=(0,255,0), flags=0)plt.imshow(img2), plt.show()
    特征匹配ORB创建一个距离测量值为cv.NORM_HAMMING的BFMatcher对象(因为我们使用的是ORB),并且启用了CrossCheck以获得更好的结果。然后,我们使用Matcher.match()方法来获取两个图像中的最佳匹配。我们按照距离的升序对它们进行排序,以使最佳匹配(低距离)排在前面。然后我们只抽出前10的匹配(只是为了提高可见度。您可以根据需要增加它)
    # 创建BF匹配器的对象bf = cv.BFMatcher(cv.NORM_HAMMING, crossCheck=True) # 匹配描述符.matches = bf.match(des1,des2) # 根据距离排序matches = sorted(matches, key = lambda x:x.distance) # 绘制前10的匹配项img3 = cv.drawMatches(img1,kp1,img2,kp2,matches[:10],None,flags=cv.DrawMatchesFlags_NOT_DRAW_SINGLE_POINTS)plt.imshow(img3),plt.show()
    matchs = bf.match(des1,des2) 行的结果是DMatch对象的列表。该DMatch对象具有以下属性:

    DMatch.distance-描述符之间的距离。越低越好
    DMatch.trainIdx-训练描述符中的描述符索引
    DMatch.queryIdx-查询描述符中的描述符索引
    DMatch.imgIdx-训练图像的索引

    带有SIFT描述符和比例测试的Brute-Force匹配使用BFMatcher.knnMatch()获得k个最佳匹配。
    import numpy as npimport cv2 as cvimport matplotlib.pyplot as pltimg1 = cv.imread('box.png',cv.IMREAD_GRAYSCALE) # 索引图像img2 = cv.imread('box_in_scene.png',cv.IMREAD_GRAYSCALE) # 训练图像# 初始化SIFT描述符sift = cv.xfeatures2d.SIFT_create()# 基于SIFT找到关键点和描述符kp1, des1 = sift.detectAndCompute(img1,None)kp2, des2 = sift.detectAndCompute(img2,None)# 默认参数初始化BF匹配器bf = cv.BFMatcher()matches = bf.knnMatch(des1,des2,k=2)# 应用比例测试good = []for m,n in matches:if m.distance < 0.75*n.distance:good.append([m])# cv.drawMatchesKnn将列表作为匹配项。img3 =cv.drawMatchesKnn(img1,kp1,img2,kp2,good,None,flags=cv.DrawMatchesFlags_NOT_DRAW_SINGLE_POINTSplt.imshow(img3),plt.show()
    基于匹配器的FLANNFLANN是近似最近邻的快速库。它包含一组算法,这些算法针对大型数据集中的快速最近邻搜索和高维特征进行了优化。对于大型数据集,它的运行速度比BFMatcher快。我们将看到第二个基于FLANN的匹配器示例。
    对于基于FLANN的匹配器,我们需要传递两个字典,这些字典指定要使用的算法,其相关参数等。第一个是IndexParams。对于各种算法,要传递的信息在FLANN文档中进行了说明。概括来说,对于SIFT,SURF等算法,您可以通过以下操作:
    FLANN_INDEX_KDTREE = 1index_params = dict(algorithm = FLANN_INDEX_KDTREE, trees = 5)
    使用ORB时,你可以参考下面。根据文档建议使用带注释的值,但在某些情况下未提供必需的参数。其他值也可以正常工作。
    FLANN_INDEX_LSH = 6index_params= dict(algorithm = FLANN_INDEX_LSH,table_number = 6, # 12key_size = 12, # 20multi_probe_level = 1) #2
    第二个字典是SearchParams。它指定索引中的树应递归遍历的次数。较高的值可提供更好的精度,但也需要更多时间。如果要更改值,请传递search_params = dict(checks = 100)
    flann = cv.FlannBasedMatcher(index_params,search_params)matches = flann.knnMatch(des1,des2,k=2)
    1  留言 2021-03-10 07:55:21
  • OpenCV+相机校准和3D重建

    相机校准相机校准至少需要10个测试图案,所需的重要输入数据是3D现实世界点集以及图像中这些点的相应2D坐标。3D点称为对象点,而2D图像点称为图像点。
    准备工作除了棋盘,我们还可以使用圆形网格。 在这种情况下,我们必须使用函数cv.findCirclesGrid()来找到模式。 较少的图像足以使用圆形网格执行相机校准。
    一旦找到拐角,就可以使用cv.cornerSubPix()来提高其精度。我们还可以使用cv.drawChessboardCorners()绘制图案。
    import numpy as npimport cv2 as cvimport glob# 终止条件criteria = (cv.TERM_CRITERIA_EPS + cv.TERM_CRITERIA_MAX_ITER, 30, 0.001)# 准备对象点, 如 (0,0,0), (1,0,0), (2,0,0) ....,(6,5,0)objp = np.zeros((6*7,3), np.float32)objp[:,:2] = np.mgrid[0:7,0:6].T.reshape(-1,2)# 用于存储所有图像的对象点和图像点的数组。objpoints = [] # 真实世界中的3d点imgpoints = [] # 图像中的2d点images = glob.glob('*.jpg')for fname in images:img = cv.imread(fname)gray = cv.cvtColor(img, cv.COLOR_BGR2GRAY)# 找到棋盘角落ret, corners = cv.findChessboardCorners(gray, (7,6), None)# 如果找到,添加对象点,图像点(细化之后)if ret == True:objpoints.append(objp)corners2 = cv.cornerSubPix(gray,corners, (11,11), (-1,-1), criteria)imgpoints.append(corners)# 绘制并显示拐角cv.drawChessboardCorners(img, (7,6), corners2, ret)cv.imshow('img', img)cv.waitKey(500)cv.destroyAllWindows()
    校准现在我们有了目标点和图像点,现在可以进行校准了。我们可以使用函数cv.calibrateCamera()返回相机矩阵,失真系数,旋转和平移矢量等。
    ret, mtx, dist, rvecs, tvecs = cv.calibrateCamera(objpoints, imgpoints,gray.shape[::-1], None, None)
    不失真现在,我们可以拍摄图像并对其进行扭曲。OpenCV提供了两种方法来执行此操作。但是,首先,我们可以使用cv.getOptimalNewCameraMatrix()基于自由缩放参数来优化相机矩阵。如果缩放参数alpha = 0,则返回具有最少不需要像素的未失真图像。因此,它甚至可能会删除图像角落的一些像素。如果alpha = 1,则所有像素都保留有一些额外的黑色图像。此函数还返回可用于裁剪结果的图像ROI。
    使用cv.undistort()这是最简单的方法。只需调用该函数并使用上面获得的ROI裁剪结果即可。
    使用remapping该方式有点困难。首先,找到从扭曲图像到未扭曲图像的映射函数。然后使用重映射功能。
    img = cv.imread('left12.jpg')h, w = img.shape[:2]newcameramtx, roi = cv.getOptimalNewCameraMatrix(mtx, dist, (w,h), 1, (w,h))# 1dst = cv.undistort(img, mtx, dist, None, newcameramtx)# 剪裁图像x, y, w, h = roidst = dst[y:y+h, x:x+w]cv.imwrite('calibresult.png', dst)# 2mapx, mapy = cv.initUndistortRectifyMap(mtx, dist, None, newcameramtx, (w,h), 5)dst = cv.remap(img, mapx, mapy, cv.INTER_LINEAR)# 裁剪图像x, y, w, h = roidst = dst[y:y+h, x:x+w]cv.imwrite('calibresult.png', dst)
    参数:重投影误差重投影误差可以很好地估计找到的参数的精确程度。重投影误差越接近零,我们发现的参数越准确。给定固有,失真,旋转和平移矩阵,我们必须首先使用cv.projectPoints()将对象点转换为图像点。然后,我们可以计算出通过变换得到的绝对值和拐角发现算法之间的绝对值范数。为了找到平均误差,我们计算为所有校准图像计算的误差的算术平均值。
    mean_error = 0for i in xrange(len(objpoints)):imgpoints2, _ = cv.projectPoints(objpoints[i], rvecs[i], tvecs[i], mtx, dist)error = cv.norm(imgpoints[i], imgpoints2, cv.NORM_L2)/len(imgpoints2)mean_error += errorprint( "total error: {}".format(mean_error/len(objpoints)) )
    姿态估计先优化。然后使用函数cv.solvePnPRansac()计算旋转和平移。一旦有了这些变换矩阵,就可以使用它们将轴点投影到图像平面上。
    for fname in glob.glob('left*.jpg'):img = cv.imread(fname)gray = cv.cvtColor(img,cv.COLOR_BGR2GRAY)ret, corners = cv.findChessboardCorners(gray, (7,6),None)if ret == True:corners2 = cv.cornerSubPix(gray,corners,(11,11),(-1,-1),criteria)# 找到旋转和平移矢量。ret,rvecs, tvecs = cv.solvePnP(objp, corners2, mtx, dist)# 将3D点投影到图像平面imgpts, jac = cv.projectPoints(axis, rvecs, tvecs, mtx, dist)img = draw(img,corners2,imgpts)cv.imshow('img',img)k = cv.waitKey(0) & 0xFFif k == ord('s'):cv.imwrite(fname[:6]+'.png', img)cv.destroyAllWindows()
    对极几何首先我们需要在两个图像之间找到尽可能多的匹配项,以找到基本矩阵。为此,我们将SIFT描述符与基于FLANN的匹配器和比率测试结合使用。
    import numpy as npimport cv2 as cvfrom matplotlib import pyplot as pltimg1 = cv.imread('myleft.jpg',0) #索引图像 # left imageimg2 = cv.imread('myright.jpg',0) #训练图像 # right imagesift = cv.SIFT()# 使用SIFT查找关键点和描述符kp1, des1 = sift.detectAndCompute(img1,None)kp2, des2 = sift.detectAndCompute(img2,None)# FLANN 参数FLANN_INDEX_KDTREE = 1index_params = dict(algorithm = FLANN_INDEX_KDTREE, trees = 5)search_params = dict(checks=50)flann = cv.FlannBasedMatcher(index_params,search_params)matches = flann.knnMatch(des1,des2,k=2)good = []pts1 = []pts2 = []# 根据Lowe的论文进行比率测试for i,(m,n) in enumerate(matches):if m.distance < 0.8*n.distance:good.append(m)pts2.append(kp2[m.trainIdx].pt)pts1.append(kp1[m.queryIdx].pt)
    现在,我们获得了两张图片的最佳匹配列表。 让我们找到基本面矩阵。
    pts1 = np.int32(pts1)pts2 = np.int32(pts2)F, mask = cv.findFundamentalMat(pts1,pts2,cv.FM_LMEDS)# 我们只选择内点pts1 = pts1[mask.ravel()==1]pts2 = pts2[mask.ravel()==1]
    接下来,我们找到Epilines。在第二张图像上绘制与第一张图像中的点相对应的Epilines。因此,在这里提到正确的图像很重要。我们得到了一行线。因此,我们定义了一个新功能来在图像上绘制这些线条。
    def drawlines(img1,img2,lines,pts1,pts2):''' img1 - 我们在img2相应位置绘制极点生成的图像lines - 对应的极点 '''r,c = img1.shapeimg1 = cv.cvtColor(img1,cv.COLOR_GRAY2BGR)img2 = cv.cvtColor(img2,cv.COLOR_GRAY2BGR)for r,pt1,pt2 in zip(lines,pts1,pts2):color = tuple(np.random.randint(0,255,3).tolist())x0,y0 = map(int, [0, -r[2]/r[1] ])x1,y1 = map(int, [c, -(r[2]+r[0]*c)/r[1] ])img1 = cv.line(img1, (x0,y0), (x1,y1), color,1)img1 = cv.circle(img1,tuple(pt1),5,color,-1)img2 = cv.circle(img2,tuple(pt2),5,color,-1)return img1,img2
    现在,我们在两个图像中都找到了Epiline并将其绘制。
    # 在右图(第二张图)中找到与点相对应的极点,然后在左图绘制极线lines1 = cv.computeCorrespondEpilines(pts2.reshape(-1,1,2), 2,F)lines1 = lines1.reshape(-1,3)img5,img6 = drawlines(img1,img2,lines1,pts1,pts2)# 在左图(第一张图)中找到与点相对应的Epilines,然后在正确的图像上绘制极线lines2 = cv.computeCorrespondEpilines(pts1.reshape(-1,1,2), 1,F)lines2 = lines2.reshape(-1,3)img3,img4 = drawlines(img2,img1,lines2,pts2,pts1)plt.subplot(121),plt.imshow(img5)plt.subplot(122),plt.imshow(img3)plt.show()
    立体图像的深度图import numpy as npimport cv2 as cvfrom matplotlib import pyplot as pltimgL = cv.imread('tsukuba_l.png',0)imgR = cv.imread('tsukuba_r.png',0)stereo = cv.StereoBM_create(numDisparities=16, blockSize=15)disparity = stereo.compute(imgL,imgR)plt.imshow(disparity,'gray')plt.show()
    结果受到高度噪声的污染。通过调整numDisparities和blockSize的值,可以获得更好的结果。
    参数:

    texture_threshold:过滤出纹理不足以进行可靠匹配
    区域斑点范围和大小:基于块的匹配器通常会在对象边界附近产生“斑点”,其中匹配窗口捕获一侧的前景和背景在另一场景中,匹配器似乎还在桌子上投影的纹理中找到小的虚假匹配项。为了消除这些伪像,我们使用由speckle_size和speckle_range参数控制的散斑滤镜对视差图像进行后处理。speckle_size是将视差斑点排除为“斑点”的像素数。speckle_range控制必须将值差异视为同一对象的一部分的程度
    视差数量:滑动窗口的像素数。它越大,可见深度的范围就越大,但是需要更多的计算
    min_disparity:从开始搜索的左像素的x位置开始的偏移量
    uniqueness_ratio:另一个后过滤步骤。如果最佳匹配视差不足够好于搜索范围中的所有其他视差,则将像素滤出。如果texture_threshold和斑点过滤仍在通过虚假匹配,则可以尝试进行调整
    prefilter_size和prefilter_cap:预过滤阶段,可标准化图像亮度并增强纹理,以准备块匹配通常,你不需要调整这些
    0  留言 2021-05-10 07:55:16
  • OpenCV+计算摄影

    图像去噪
    cv.fastNlMeansDenoising()-处理单个灰度图像
    cv.fastNlMeansDenoisingColored()-处理彩色图像。
    cv.fastNlMeansDenoisingMulti()-处理在短时间内捕获的图像序列(灰度图像)
    cv.fastNlMeansDenoisingColoredMulti()-与上面相同,但用于彩色图像。

    常用参数为:

    h:决定滤波器强度的参数。较高的h值可以更好地消除噪点,但同时也可以消除图像细节。(可以设为10)
    hForColorComponents:与h相同,但仅用于彩色图像。(通常与h相同)
    templateWindowSize:应为奇数。(建议设为7)
    searchWindowSize:应为奇数。(建议设为21)

    图像修补我们需要创建一个与输入图像大小相同的掩码,其中非零像素对应于要修复的区域。
    import numpy as npimport cv2 as cvimg = cv.imread('messi_2.jpg')mask = cv.imread('mask2.png',0)dst = cv.inpaint(img,mask,3,cv.INPAINT_TELEA)cv.imshow('dst',dst)cv.waitKey(0)cv.destroyAllWindows()
    高动态范围将曝光图像加载到列表中将曝光合成HDR图像在此阶段,我们将曝光序列合并为一张HDR图像,显示了OpenCV中的两种可能性。 第一种方法是Debevec,第二种方法是Robertson。 请注意,HDR图像的类型为float32,而不是uint8,因为它包含所有曝光图像的完整动态范围。
    import cv2 as cvimport numpy as np# 将曝光图像加载到列表中img_fn = ["img0.jpg", "img1.jpg", "img2.jpg", "img3.jpg"]img_list = [cv.imread(fn) for fn in img_fn]exposure_times = np.array([15.0, 2.5, 0.25, 0.0333], dtype=np.float32)# 将曝光合成HDR图像merge_debevec = cv.createMergeDebevec()hdr_debevec = merge_debevec.process(img_list, times=exposure_times.copy())merge_robertson = cv.createMergeRobertson()hdr_robertson = merge_robertson.process(img_list, times=exposure_times.copy())
    色调图HDR图像我们将32位浮点HDR数据映射到[0..1]范围内。实际上,在某些情况下,该值可以大于1或小于0,因此请注意,我们稍后将必须裁剪数据以避免溢出。
    # 色调图HDR图像tonemap1 = cv.createTonemap(gamma=2.2)res_debevec = tonemap1.process(hdr_debevec.copy())
    使用Mertens融合曝光在这里,我们展示了一种替代算法,用于合并曝光图像,而我们不需要曝光时间。我们也不需要使用任何色调映射算法,因为Mertens算法已经为我们提供了[0..1]范围内的结果。
    # 使用Mertens融合曝光merge_mertens = cv.createMergeMertens()res_mertens = merge_mertens.process(img_list)
    转为8-bit并保存为了保存或显示结果,我们需要将数据转换为[0..255]范围内的8位整数。
    # 转化数据类型为8-bit并保存res_debevec_8bit = np.clip(res_debevec*255, 0, 255).astype('uint8')res_robertson_8bit = np.clip(res_robertson*255, 0, 255).astype('uint8')res_mertens_8bit = np.clip(res_mertens*255, 0, 255).astype('uint8')cv.imwrite("ldr_debevec.jpg", res_debevec_8bit)cv.imwrite("ldr_robertson.jpg", res_robertson_8bit)cv.imwrite("fusion_mertens.jpg", res_mertens_8bit)
    0  留言 2021-05-06 08:09:30
  • 编程实现MFC程序窗口一运行立马隐藏

    背景MFC程序在启动显示窗口之前,就已经做了很多关于界面初始化的操作。如果对WIN32 API函数较为熟悉的同学就会认为,让窗口隐藏,直接调用 ShowWindow 函数,将窗口设置为隐藏就可以了。是的,ShowWindow 函数可以隐藏窗口没错。但是,这个函数要成功实现的窗口隐藏有一个前提条件,就是窗口界面初始化已经完成,而且窗口界面你已经显示完全了。这时,再调用 ShowWindow 函数去隐藏窗口,这是可以的。
    但是,本文要实现的是,窗口程序一运行就已经开始隐藏的功能,而不是显示后隐藏。也就是说,在窗口界面初始化阶段,窗口界面还没有显示的时候,就已经开始隐藏界面了。这样的隐藏,使得程序运行无声无息。
    现在,我们把这个程序的实现过程整理成文档,分享给大家。
    函数介绍MoveWindow 函数
    改变指定窗口的位置和大小。对子窗口来说,位置和大小取决于父窗口客户区的左上角;对于Owned窗口,位置和大小取决于屏幕左上角。
    函数声明
    BOOL MoveWindow( HWND hWnd, int X, int Y, int nWidth, int nHeight, BOOL bRepaint );
    参数

    hWnd [in]窗口的句柄。X [in]窗口左侧的新位置。Y [in]窗口顶部的新位置。nWidth [in]窗口的新宽度。nHeight [in]窗口的新高度。bRepaint [in]指示窗口是否要重画。 如果此参数为TRUE,窗口将收到一条消息。 如果参数为FALSE,则不会发生任何重画。 这适用于客户端区域,非客户区域(包括标题栏和滚动条),父窗口的任何部分由于移动子窗口而被覆盖。
    返回值

    如果函数成功,则返回值不为零。如果函数失败,返回值为零。 要获取扩展错误信息,请调用GetLastError。

    GetWindowLong 函数
    获取有关指定窗口的信息。 函数也获得在额外窗口内存中指定偏移位地址的32位度整型值。
    函数声明
    LONG GetWindowLong( HWND hWnd, int nlndex );
    参数

    hWnd目标窗口的句柄。它可以是窗口句柄及间接给出的窗口所属的窗口类。
    nlndex需要获得的相关信息的类型。要获得任意其他值,指定下列值之一:




    VALUE
    MEANING




    GWL_EXSTYLE
    获得扩展窗口风格。


    GWL_HINSTANCE
    获得应用实例的句柄


    GWL_HWNDPARENT
    如果父窗口存在,获得父窗口句柄


    GWL_ID
    获得窗口标识


    GWL_STYLE
    获得窗口风格


    GWL_USERDATA
    获得与窗口有关的32位值。每一个窗口均有一个由创建该窗口的应用程序使用的32位值


    GWL_WNDPROC
    获得窗口过程的地址,或代表窗口过程的地址的句柄。必须使用CallWindowProc函数调用窗口过程



    hWnd参数为对话框句柄时,还可用下列值:



    VALUE
    MEANING




    DWL_DLGPROC
    获得对话框过程的地址,或一个代表对话框过程的地址的句柄。必须使用函数CallWindowProc来调用对话框过程


    DWL_MSGRESULT
    获得在对话框过程中一个消息处理的返回值


    DWL_USER
    获得应用程序私有的额外信息,例如一个句柄或指针



    返回值

    如果函数成功,返回值是所需的32位值;如果函数失败,返回值是0。若想获得更多错误信息请调用 GetLastError函数。

    SetWindowLong 函数
    用来改变指定窗口的属性.函数也将指定的一个32位值设置在窗口的额外存储空间的指定偏移位置。
    函数声明
    LONG SetWindowLong( HWND hWnd, // handle to window int nlndex, // offset of value to set LONG dwNewLong // new value);
    参数

    hWnd窗口句柄及间接给出的窗口所属的类。nlndex设置相关信息的类型。要获得任意其他值,指定下列值之一(和上面 GetWindowLong 函数的 nIndex 值相同)。dwNewLong指定的替换值。
    返回值

    如果函数成功,返回值是指定的32位整数的原来的值。如果函数失败,返回值为0。若想获得更多错误信息,请调用GetLastError函数。

    实现原理窗口移动到显示屏幕之外要设置程序窗口显示的位置和大小,我们可以直接调用 MoveWindow 函数,设置移动后窗口显示的位置坐标、窗口大小。这时,我们只需要将窗口大小都设为 0 ,位置坐标都设为-1000(屏幕位置坐标以屏幕左上角为起点),这样窗口就在屏幕之外显示了。
    隐藏任务栏程序图标其中,我们先来了解 GWL_EXSTYLE 窗口拓展属性中的两个值的含义,这是要理解隐藏任务栏比较关键的一步:
    一是 WS_EX_APPWINDOW,表示当窗口可见时,将一个顶层窗口放置到任务条上;
    二是 WS_EX_TOOLWINDOW,表示创建工具窗口,即窗口是一个游动的工具条。工具窗口的标题条比一般窗口的标题条短,并且窗口标题以小字体显示。工具窗口不在任务栏里显示,当用户按下alt+Tab键时工具窗口不在对话框里显示。如果工具窗口有一个系统菜单,它的图标也不会显示在标题栏里,但是,可以通过点击鼠标右键或Alt+Space来显示菜单。
    由上面 WS_EX_APPWINDOW 和 WS_EX_TOOLWINDOW 可知,我们要想实现任务栏程序的隐藏。那么,就要把 WS_EX_APPWINDOW 值去掉,然后再增加值 WS_EX_TOOLWINDOW。所以:

    首先调用 GetWindowLong 函数获取窗口 GWL_EXSTYLE 属性的值 dwOldStyle;
    然后,去掉 WS_EX_APPWINDOW 值,即
    dwOldStyle & (~WS_EX_APPWINDOW)
    接着,增加 WS_EX_APPWINDOW 值,即
    dwNewStyle = dwNewStyle | WS_EX_TOOLWINDOW;
    最后,调用 SetWindowLong 将新的 GWL_EXSTYLE 属性的值重新设置,这样就完成了。

    编码实现// 隐藏窗口void HideWindow(HWND hWnd){ // 把窗口移动到屏幕显示之外, 窗口大小都设为 0 ::MoveWindow(hWnd, -1000, -1000, 0, 0, FALSE); // 先获取原来窗口的拓展风格 DWORD dwOldStyle = ::GetWindowLong(hWnd, GWL_EXSTYLE); // 设置新属性, 隐藏任务栏程序图标 DWORD dwNewStyle = dwOldStyle & (~WS_EX_APPWINDOW); dwNewStyle = dwNewStyle | WS_EX_TOOLWINDOW; ::SetWindowLong(hWnd, GWL_EXSTYLE, dwNewStyle);}
    总结我们隐藏窗口的思路就两点:一是把窗口的显示位置坐标移到屏幕之外,这样窗口显示的时候,在屏幕之内是看不到的;二是把任务栏的程序图标隐藏,因为第一步操作会因为任务栏下的图标露出马脚,所以,必须隐藏任务栏中程序的图标。这样,就可以实现一运行程序,窗口就隐藏了。
    大家要注意,虽然窗口隐藏了,我们打开任务管理器还是会看到我们程序的进程的。所以,关于进程隐藏,就是另一个不同知识点了。
    参考参考自《Windows黑客编程技术详解》一书
    2  留言 2018-12-20 12:32:48

发送私信

我也许不完美,但我一直在做自己

19
文章数
31
评论数
eject