opencv 卡尺法 测量边缘距离
参考来源 :https://github.com/crackwitz/metrology-demo

前言
一、测量方法
二、测量步骤
1.获取直线的像素
2.高斯滤波平滑曲线
3.计算跳变幅度值
4.计算距离值
5.显示和保存图片
总结
前言
halcon中有按照直线找边缘测量距离的工具,但是opencv中没有类似的工具可以直接实现该测量方式,参考网上的实现方式,可以实现。

测量的效果贴图


一、测量方法
根据测量线的两个端点,获取直线的像素,然后进行滤波过滤噪点,计算跳变幅度,获取最大最小值的位置,计算距离

二、测量步骤
1.获取直线的像素
将直线的通过仿射变换转成1D的图像,可以采用亚像素的算法,先获取仿射变换的矩阵

代码如下(示例):

def build_transform(p0, p1, stride=None, nsamples=None):"builds an affine transform with x+ along defined line"# use one of stride (in pixels) or nsamples (absolute value)(x0, y0) = p0(x1, y1) = p1dx = x1 - x0dy = y1 - y0length = np.hypot(dx, dy)if nsamples is not None:#stride = length / nsamplesfactor = 1 / nsampleselse:if stride is None:stride = 1.0factor = stride / lengthnsamples = int(round(length / stride))# map: src <- dst (use WARP_INVERSE_MAP flag for warpAffine)H = np.eye(3, dtype=np.float64) # homographyH[0:2, 0] = (dx, dy) # x unit vectorH[0:2, 1] = (-dy, dx) # y unit vector is x rotated by 90 degreesx=H[0:2, 0:2]H[0:2, 0:2] *= factorH[0:2, 2] = (x0, y0) # translate onto starting point# take affine part of homographyassert np.isclose(a=H[2], b=(0,0,1)).all() # we didn't touch those but let's better checkA = H[0:2, :]return (nsamples, A)

然后再采用变换的方法获取图像的像素值

def sample_opencv(im, M, nsamples):# use transform to get samples# available: INTER_{NEAREST,LINEAR,AREA,CUBIC,LANCOS4)samples = cv.warpAffine(im, M=M, dsize=(nsamples, 1), flags=cv.WARP_INVERSE_MAP | cv.INTER_CUBIC )# flatten row vectorsamples.shape = (-1,)# INTER_CUBIC seems to break down beyond 1/32 sampling (discretizes).# there might be fixed point algorithms at workreturn samples

2.高斯滤波平滑曲线
samples = scipy.ndimage.gaussian_filter1d(samples, sigma=args.sigma / args.stride)
1
3.计算跳变幅度值
# off-by-half in position because for values [0,1,1,0] this returns [+1,0,-1]
gradient = np.diff(samples) / args.stride

4.计算距离值
    i_falling = np.argmin(gradient) # in samples
    i_rising = np.argmax(gradient) # in samples
    distance = np.abs(i_rising - i_falling) * args.stride # in pixels

完整代码:

#!/usr/bin/env python3import sys
import argparse
import numpy as np
import cv2
import scipy.ndimage### "business logic" ###################################################def build_transform(p0, p1, stride=None, nsamples=None):"builds an affine transform with x+ along defined line"# use one of stride (in pixels) or nsamples (absolute value)(x0, y0) = p0(x1, y1) = p1dx = x1 - x0dy = y1 - y0length = np.hypot(dx, dy)if nsamples is not None:# stride = length / nsamplesfactor = 1 / nsampleselse:if stride is None:stride = 1.0factor = stride / lengthnsamples = int(round(length / stride))# map: src <- dst (use WARP_INVERSE_MAP flag for warpAffine)H = np.eye(3, dtype=np.float64)  # homographyH[0:2, 0] = (dx, dy)  # x unit vectorH[0:2, 1] = (-dy, dx)  # y unit vector is x rotated by 90 degreesH[0:2, 0:2] *= factorH[0:2, 2] = (x0, y0)  # translate onto starting point# take affine part of homographyassert np.isclose(a=H[2], b=(0, 0, 1)).all()  # we didn't touch those but let's better checkA = H[0:2, :]return (nsamples, A)def sample_opencv(im, M, nsamples):# use transform to get samples# available: INTER_{NEAREST,LINEAR,AREA,CUBIC,LANCOS4)samples = cv2.warpAffine(im, M=M, dsize=(nsamples, 1), flags=cv2.WARP_INVERSE_MAP | cv2.INTER_CUBIC)# flatten row vectorsamples.shape = (-1,)# INTER_CUBIC seems to break down beyond 1/32 sampling (discretizes).# there might be fixed point algorithms at workreturn samplesdef sample_scipy(im, M, nsamples):# coordinates to this function are (i,j) = (y,x)# I could permute first and second rows+columns of M, or transpose input+outputMp = M.copy()Mp[(0, 1), :] = Mp[(1, 0), :]  # permute rowsMp[:, (0, 1)] = Mp[:, (1, 0)]  # permute columnssamples = scipy.ndimage.interpolation.affine_transform(input=im, matrix=Mp, output_shape=(1, nsamples), order=2,# 1: linear (C0, f' is piecewise constant), 2: C1 (f' is piecewise linear), 3: C2... https://en.wikipedia.org/wiki/Smoothnessmode='nearest'  # border handling)# flatten row vectorsamples.shape = (-1,)return samples### command line parsing utility functions #############################def parse_linestr(arg):pieces = arg.split(",")pieces = [float(el) for el in pieces]x0, y0, x1, y1 = piecesreturn ((x0, y0), (x1, y1))def parse_bool(arg):if isinstance(arg, bool):return argif arg.lower() in ('yes', 'true', 't', 'y', '1'):return Trueelif arg.lower() in ('no', 'false', 'f', 'n', '0'):return Falseelse:raise argparse.ArgumentTypeError(f'Boolean value expected, got {arg!r} instead')def parse_float(arg):import astif '/' in arg:num, denom = arg.split('/', 1)num = ast.literal_eval(num)denom = ast.literal_eval(denom)result = num / denomelse:result = ast.literal_eval(arg)return result### main... ############################################################if __name__ == '__main__':# command line argument parsing# change defaults hereparser = argparse.ArgumentParser()parser.add_argument("--picture", dest="fname", metavar="PATH", type=str, default="dish-1.jpg", help="path to picture file")parser.add_argument("--invert", type=parse_bool, default=True, metavar="BOOL", help="invert picture (cosmetic; distance between gradient extrema is absolute)")parser.add_argument("--line", type=parse_linestr, default=((1320, 2500), (1320, 2100)), metavar="X0,Y0,X1,Y1", help="line to sample on")parser.add_argument("--stride", type=parse_float, default=1 / 4, metavar="PX", help="stride in pixels to sample along line, fractions supported")parser.add_argument("--method", type=lambda s: s.lower(), default="opencv", help="sampling methods: SciPy (slower, smoother, default), OpenCV (faster, less smooth)")parser.add_argument("--sigma", type=float, default=2.0, metavar="PX", help="sigma for gaussian lowpass on sampled signal, before gradient is calculated")parser.add_argument("--verbose", type=parse_bool, default=True, metavar="BOOL", help="chatty or not")parser.add_argument("--display", type=parse_bool, default=True, metavar="BOOL", help="draw some plots")parser.add_argument("--saveplot", type=str, default="plot.png", metavar="PATH", help="save a picture (use '--saveplot=' to disable)")args = parser.parse_args()########## here be dragons ##########if args.stride > 1:print(f"WARNING: stride should be <= 1, is {args.stride}")stride_decimals = max(0, int(np.ceil(-np.log10(args.stride))))if args.verbose: print("loading picture...", end=" ", flush=True)im = cv2.imread(args.fname, cv2.IMREAD_GRAYSCALE)imh, imw = im.shape[:2]if args.invert:im = 255 - im  # invertim = im.astype(np.float32)  # * np.float32(1/255)if args.verbose: print("done")# build transformp0, p1 = args.linensamples, M = build_transform(p0, p1, stride=args.stride)if args.verbose: print(f"taking {nsamples} samples along line {p0} -> {p1}...", end=" ", flush=True)# pick oneif args.method == 'opencv':samples = sample_opencv(im, M, nsamples)  # does "normal" cubic (4x4 support points, continuous first derivative)elif args.method == 'scipy':samples = sample_scipy(im, M, nsamples)  # does some fancy "cubic" with continuous higher derivativeselse:assert False, "method needs to be opencv or scipy"if args.verbose: print("sampling done")# smoothing to remove noiseif args.sigma > 0:if args.verbose: print(f"lowpass filtering with sigma = {args.sigma} px...", end=" ", flush=True)samples = scipy.ndimage.gaussian_filter1d(samples, sigma=args.sigma / args.stride)if args.verbose: print("done")# off-by-half in position because for values [0,1,1,0] this returns [+1,0,-1]gradient = np.diff(samples) / args.stridei_falling = np.argmin(gradient)  # in samplesi_rising = np.argmax(gradient)  # in samplesdistance = np.abs(i_rising - i_falling) * args.stride  # in pixelsif args.verbose:print(f"distance: {distance:.{stride_decimals}f} pixels")else:print(distance)# this was the result. algorithm is done.# now follows displaying codeif args.display:gradient *= 255 / np.abs(gradient).max()# plot signalplot = cv2.plot.Plot2d_create(np.arange(nsamples, dtype=np.float64), samples.astype(np.float64))plot.setMinY(256 + 32)plot.setMaxY(-32)plot.setMinX(0)plot.setMaxX(nsamples)plot.setGridLinesNumber(5)plot.setShowText(False)  # callout for specific point, setPointIdxToPrint(index)plot.setPlotGridColor((64,) * 3)canvas1 = plot.render()# plot gradientplot = cv2.plot.Plot2d_create(np.arange(nsamples - 1) + 0.5, gradient.astype(np.float64))plot.setMinY(256 + 64)plot.setMaxY(-256 - 64)plot.setMinX(0)plot.setMaxX(nsamples)plot.setGridLinesNumber(5)plot.setShowText(False)  # callout for specific point, setPointIdxToPrint(index)plot.setPlotGridColor((64,) * 3)canvas2 = plot.render()# arrange verticallycanvas = np.vstack([canvas1, canvas2])  # 600 wide, 800 tall# draw lines at edges (largest gradients)# plots are 600x400 pixels... and there's no way to plot multiple or plot lines in "plot space"px_falling = int(600 * (i_falling + 0.5) / nsamples)px_rising = int(600 * (i_rising + 0.5) / nsamples)cv2.line(canvas, (px_falling, 0), (px_falling, 400 * 2), color=(255, 0, 0))cv2.line(canvas, (px_rising, 0), (px_rising, 400 * 2), color=(255, 0, 0))# some text to describe the picturecv2.putText(canvas, f"{nsamples * args.stride:.0f} px, {p0} -> {p1}", (10, 350), cv2.FONT_HERSHEY_SIMPLEX, 0.75, (255, 255, 255), thickness=1, lineType=cv2.LINE_AA)cv2.putText(canvas, f"stride {args.stride} px, {nsamples} samples, sigma {args.sigma}", (10, 350 + 35), cv2.FONT_HERSHEY_SIMPLEX, 0.75, (255, 255, 255), thickness=1, lineType=cv2.LINE_AA)cv2.putText(canvas, f"distance: {distance:.{stride_decimals}f} px", (10, 350 + 70), cv2.FONT_HERSHEY_SIMPLEX, 0.75, (255, 255, 255), thickness=1, lineType=cv2.LINE_AA)# save for posterityif args.saveplot:cv2.imwrite(args.saveplot, canvas)if args.display:cv2.imshow("plot", canvas)if args.verbose:print("press Ctrl+C in the terminal, or press any key while the imshow() window is focused")while True:keycode = cv2.waitKey(100)if keycode == -1:continue# some key...if args.verbose:print(f"keycode: {keycode}")cv2.destroyAllWindows()break

总结
提示:显示的程序包含了opencv pilo,这个需要引入opencv-contrib-python模块:

原文链接:https://blog.csdn.net/hong3731/article/details/119649418

使用过程报错:

module 'cv2' has no attribute 'plot'

python opencv卡尺测量边缘距离相关推荐

  1. opencv 卡尺法 测量边缘距离

    opencv 卡尺法 测量边缘距离 参考来源 :https://github.com/crackwitz/metrology-demo 文章目录 opencv 卡尺法 测量边缘距离 前言 一.测量方法 ...

  2. 使用Python+OpenCV+detectorn2实现社交距离检测

    点击上方"小白学视觉",选择加"星标"或"置顶" 重磅干货,第一时间送达 介绍 美国和欧洲的许多城市现在都在谨慎地重新开放.人们被要求在外出 ...

  3. 用 Python 和 OpenCV 来测量相机到目标的距离

    用 Python 和 OpenCV 来测量相机到目标的距离 http://python.jobbole.com/84378/ 几天前,一个叫 Cameron 的 PyImageSearch 读者发来邮 ...

  4. python+opencv实现机器视觉基础技术(2)(宽度测量,缺陷检测,医学检测

     本篇博客接着讲解机器视觉的有关技术和知识.包括宽度测量,缺陷检测,医学处理. 一:宽度测量   在传统的自动化生产中,对于尺寸的测量,典型的方法就是千分尺.游标卡尺.塞尺等.而这些测量手段测量精度低 ...

  5. python opencv二值化图像_python opencv,读取彩色图像,提取三通道,图像二值化,提取图像的边缘...

    python opencv,读取彩色图像,提取三通道,图像二值化,提取图像的边缘 python opencv 1,读取图像 2,图像变矩阵 3,图像转灰度图像 4,彩色图像是3D数组 5,灰度图像是2 ...

  6. Python OpenCV 边缘滤波保留(EPF)

    Python OpenCV 365 天学习计划,与橡皮擦一起进入图像领域吧. Python OpenCV 基础知识铺垫 函数原型介绍 高斯双边滤波 均值迁移滤波 橡皮擦的小节 基础知识铺垫 前几篇博客 ...

  7. Python+OpenCV实现自动扫雷,挑战扫雷世界记录!

    点击上方"小白学视觉",选择加"星标"或"置顶" 重磅干货,第一时间送达 本文转载自知乎Artrix https://zhuanlan.zh ...

  8. Python+OpenCV实现自动扫雷,创造属于自己的世界记录!

    点击上方"小白学视觉",选择加"星标"或"置顶" 重磅干货,第一时间送达 本文转载自知乎Artrix https://zhuanlan.zh ...

  9. opencv 通过网络连接工业相机_单目摄像机测距(python+opencv)

    点击上方"新机器视觉",选择加"星标"或"置顶" 重磅干货,第一时间送达 我的论文方向目前是使用单目摄像头实现机器人对人的跟随,首先单目摄像 ...

最新文章

  1. jquery学习之重要知识点
  2. numpy 笔记:finfo
  3. ai人工智能_人工智能能力问答中的人工智能不确定性
  4. Maven学习总结(44)——Maven构建时生命周期及其常用集成命令详解
  5. Linux c开发工程师的面试题,C+工程师常见的面试题总结
  6. php curl post登录与带cookie模拟登录随笔
  7. JZOJ5946. 【NOIP2018模拟11.02】时空幻境(braid)
  8. 【面试算法题】一维消除游戏
  9. Ubuntu系统实现简单c语言编程
  10. Spring:Spring支持的bean作用域有哪些
  11. 当前上下文中不存在名称 ViewBag
  12. Mysql 复制表结构
  13. maven html项目自动版本控制(时间戳) com.google.code.maven-replacer-plugin插件 前端代码自动添加版本号
  14. [附源码]Nodejs计算机毕业设计基于Yigo平台库房管理系统Express(程序+LW)
  15. SequoiaDB巨杉数据库成为唯一入选 “硅谷2016 大数据地形图”中国厂商, 企业级市场超越MongoDB等海外产品
  16. Fatal error loading the DB: Permission denied. Exiting.
  17. 基于web的员工信息管理系统
  18. allegro 倒圆角
  19. 报错https://chat.openai.com/ api/auth/ session 429怎么办
  20. 汉语是世界上最好的语言

热门文章

  1. linux c 进程间通信
  2. tcpdump for Android 移动端抓包
  3. DDoS CC 攻防
  4. %00截断攻击的探索
  5. windows平台下 c++获取 系统版本 网卡 内存 CPU 硬盘 显卡信息
  6. linux5.4iso,Redhat Linux5.4/5.5/5.8/6.0/6.3 ISO镜像文件下载
  7. CMake常见变量——Project和CMake相关信息
  8. 最清楚的mmap()详解与源码分析
  9. db2 日期英式写法_《学霸英语》16:美国人和英国人“表达日期”,差距竟然这么大!...
  10. html自适应pc窗口大小_自适应技术很难吗?为什么Shopyy平台将网站分为PC端和移动端...