智能机器人实验——机械臂画画
实验器材Dobot机械臂笔小型摄像头电脑软件白纸项目描述创意来源前段时间有个团队实现了通过手机拍照将照片传到机器中机器实现画图。于是想着通过Dobot机械臂实现同样甚至更好的功能。在实验指导书上看到Dobot机械臂能够简单的进行写字就联想到能够用它来画画由摄像头实时拍摄对象同时对显示的图像进行卡通化与素描化展示较好的效果最后输出图像到机械臂上让机械臂作图。实现功能1、通过python opencv包调用摄像头实现摄像头的图像实现2、对于每一帧的视频图像进行卡通化与素描化处理3、通过键盘控制摄像头进行拍照并将照片保存4、编写程序将图片从jpg格式转成svg矢量图格式将转化出的矢量图导入dobot模块控制机械臂绘图。算法实现1、图片卡通化算法def cartoon(image): gray cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) gray cv2.medianBlur(gray, 7) edges cv2.adaptiveThreshold(gray, 255, cv2.ADAPTIVE_THRESH_MEAN_C, cv2.THRESH_BINARY, 9, 10) color cv2.bilateralFilter(image, 12, 250, 250) cartoon cv2.bitwise_and(color, color, maskedges) return cartoon2、图片素描化算法def sumiao(image): cartoon_image1, cartoon_image2 cv2.pencilSketch(image, sigma_s60, sigma_r0.15, shade_factor0.05) return cartoon_image13、图片格式转化算法def bitmap_to_contour_svg(input_bitmap_path: str, output_svg_path: str): img cv2.imread(input_bitmap_path) dump_rings_from_image(img, output_pathoutput_svg_path) remove_matplotlib_background(output_svg_path)4、拍摄及主程序if cap.isOpened() is True: # 检查摄像头是否正常启动 while (True): # 获取摄像头拍摄到的画面 ret, frame cap.read() img frame cartoon1cartoon(img) sumiao1sumiao(img) stylish1stylish(img) # 实时展示效果画面 # cv2.imshow(frame1, frame) cv2.imshow(frame2,stylish1) cv2.imshow(frame, sumiao1) # 每5毫秒监听一次键盘动作 if cv2.waitKey(5) 0xFF ord(p): cv2.imwrite(pic_%d.jpg%i,stylish1) i 1 bmp_to_svg.bitmap_to_contour_svg(input_bitmap_pathpic_0.jpg, output_svg_pathpictuce_0.svg) if cv2.waitKey(5) 0xFF ord(q): break # 最后关闭所有窗口 cap.release() cv2.destroyAllWindows() else: print(cap is not opened!)呈现效果完整代码import cv2 import bmp_to_svg cap cv2.VideoCapture(0) i0 def cartoon(image): gray cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) gray cv2.medianBlur(gray, 7) edges cv2.adaptiveThreshold(gray, 255, cv2.ADAPTIVE_THRESH_MEAN_C, cv2.THRESH_BINARY, 9, 10) color cv2.bilateralFilter(image, 12, 250, 250) cartoon cv2.bitwise_and(color, color, maskedges) return cartoon def sumiao(image): cartoon_image1, cartoon_image2 cv2.pencilSketch(image, sigma_s60, sigma_r0.15, shade_factor0.05) return cartoon_image1 def stylish(image): # 风格化 cartoon_image cv2.stylization(image, sigma_s150, sigma_r0.45) return cartoon_image if cap.isOpened() is True: # 检查摄像头是否正常启动 while (True): # 获取摄像头拍摄到的画面 ret, frame cap.read() img frame cartoon1cartoon(img) sumiao1sumiao(img) stylish1stylish(img) # 实时展示效果画面 # cv2.imshow(frame1, frame) cv2.imshow(frame2,stylish1) cv2.imshow(frame, sumiao1) # 每5毫秒监听一次键盘动作 if cv2.waitKey(5) 0xFF ord(p): cv2.imwrite(pic_%d.jpg%i,stylish1) i 1 bmp_to_svg.bitmap_to_contour_svg(input_bitmap_pathpic_0.jpg, output_svg_pathpictuce_0.svg) if cv2.waitKey(5) 0xFF ord(q): break # 最后关闭所有窗口 cap.release() cv2.destroyAllWindows() else: print(cap is not opened!)bmp_to_svg.py文件from typing import Iterable, List, Tuple, Union import cv2 import matplotlib.pyplot as plt import numpy as np from xml.dom import minidom as md from queue import Queue import warnings def look_shape(a: Iterable) - Tuple: # for debug return np.array(a).shape def length_within_points(a: Iterable, empty_value: Union[int, float] 0) - int: a simple instance: array : [empty_value, empty_value, empty_value, 1, empty_value, 0, 1, 2, empty_value] Then length_within_points(array) will return index diff between 1 and 2, which is 5 a list(a) l_pivot, r_pivot -1, -2 for index, (l_val, r_val) in enumerate(zip(a[::1], a[::-1])): if l_val ! empty_value and l_pivot -1: l_pivot index if r_val ! empty_value and r_pivot -2: r_pivot len(a) - index return r_pivot - l_pivot 1 def dump_rings_from_image(image: np.ndarray, output_path: str, plot_dict: dict {color: k, linewidth: 2.0}, default_height: float 8) - List[np.ndarray]: # regular operation, no more explainations blur cv2.GaussianBlur(image, (3, 3), 0) gray cv2.cvtColor(blur, cv2.COLOR_BGR2GRAY) edge cv2.Canny(gray, 50, 150) # get ratio between width and height to adjust the final output valid_width length_within_points(edge.sum(axis0)) valid_height length_within_points(edge.sum(axis1)) true_ratio valid_width / valid_height # get contour of the edge image contour_tuple cv2.findContours(edge, modecv2.RETR_TREE, methodcv2.CHAIN_APPROX_NONE) contours contour_tuple[0] rings [np.array(c).reshape([-1, 2]) for c in contours] # adjust coordinate system to the image coordinate system max_x, max_y, min_x, min_y 0, 0, 0, 0 for ring in rings: max_x max(max_x, ring.max(axis0)[0]) max_y max(max_y, ring.max(axis0)[1]) min_x max(min_x, ring.min(axis0)[0]) min_y max(min_y, ring.min(axis0)[1]) # adjust ratio plt.figure(figsize[default_height * true_ratio, default_height]) # plot to the matplotlib for _, ring in enumerate(rings): close_ring np.vstack((ring, ring[0])) xx close_ring[..., 0] yy max_y - close_ring[..., 1] plt.plot(xx, yy, **plot_dict) plt.axis(off) plt.savefig(output_path) def remove_matplotlib_background(svg_file: str, bg_node_name: str patch_1) - None: dom_tree: md.Document md.parse(svg_file) svg_node None # select the svg tag for node in dom_tree.childNodes: if node.nodeName svg: svg_node: md.Element node if svg_node is None: raise ValueError(not find a svg node in {}.format(svg_file)) # bfs svg node to find the background node q Queue() q.put(svg_node) target_node None # we will remove the target node while not q.empty(): cur: md.Node q.get() if cur.hasChildNodes(): for node in cur.childNodes: q.put(node) if hasattr(cur, getAttribute): # this is the id of the background node if cur.getAttribute(id) bg_node_name: target_node cur if target_node is None: warnings.warn(background node is not found, please ensure whether bg_node_name is correct) else: # remove and write target_node.parentNode.removeChild(target_node) with open(svg_file, w, encodingutf-8) as fp: dom_tree.writexml( writerfp, indent\t ) def bitmap_to_contour_svg(input_bitmap_path: str, output_svg_path: str): img cv2.imread(input_bitmap_path) dump_rings_from_image(img, output_pathoutput_svg_path) remove_matplotlib_background(output_svg_path) if __name__ __main__: bitmap_to_contour_svg( input_bitmap_pathpic_1_0.jpg, output_svg_path5.svg )

相关新闻

苏州简易注销失败,企业该如何走一般注销流程?

苏州简易注销失败,企业该如何走一般注销流程?

一条路走不通,换条路也得走完——注销这件事,拖越久代价越大 很多老板觉得简易注销被驳回了,干脆就不管了。但真相是:不注销的后果,比注销麻烦一百倍。法人被限制高消费、银行账户被冻结、甚至影响子女读书——这些都不…

2026/11/13 2:29:46 阅读更多 →
抖音批量下载神器Douzy:一键保存无水印视频的完整指南

抖音批量下载神器Douzy:一键保存无水印视频的完整指南

抖音批量下载神器Douzy:一键保存无水印视频的完整指南 【免费下载链接】douyin-downloader A practical Douyin downloader for both single-item and profile batch downloads, with progress display, retries, SQLite deduplication, and browser fallback suppo…

2026/11/6 9:01:30 阅读更多 →
Zigbee、STM32系列开发板-非定时器方式实现PWM呼吸灯-实时状态更改方法-呼吸灯简易实现方法

Zigbee、STM32系列开发板-非定时器方式实现PWM呼吸灯-实时状态更改方法-呼吸灯简易实现方法

一、概述 本文讲述关于PWM呼吸灯不使用定时器的呼吸方式,并且可以实现随时暂停至某一单个亮度的PWM调光程序,具有非常高的实时性,对外界改变操作实时做出反馈。 二、实现思路 本文的实现思路是以非定时器PWM实现的,需要先学习文章…

2026/11/3 6:36:13 阅读更多 →

最新新闻

Electron桌面应用开发实战:从环境搭建到打包发布全流程

Electron桌面应用开发实战:从环境搭建到打包发布全流程

做前端这些年,我大部分时间都在跟浏览器标签页打交道,直到第一次把桌面应用跑起来,才发现原来自己一直被限制在地址栏和刷新按钮围起来的框框里。Electron这个词,最开始是在某段时间频繁出现在同事的讨论里,一个用HTML…

2026/11/13 5:13:25 阅读更多 →
滑盖智能锁T109深度解析:结构原理、安装调试与故障排查

滑盖智能锁T109深度解析:结构原理、安装调试与故障排查

简介:亚太天能T109滑盖智能锁产品说明书是一份PDF格式的官方技术文档,主要面向智能锁安装人员、终端用户及售后维护者,帮助快速掌握产品安装、配置与常见故障处理。全包仅1个PDF文件,大小4.37MB,内容结构清晰&#xff…

2026/11/13 5:13:25 阅读更多 →
PMSM弱磁控制原理与Simulink建模:高速AGV驱动系统设计指南

PMSM弱磁控制原理与Simulink建模:高速AGV驱动系统设计指南

上个月我在调试一台高速AGV的驱动系统,整车要求空载跑到8m/s,电机转速已经拉到额定点,驱动器的输出电压也顶到了母线电压极限附近。再往上踩速度指令,转速纹丝不动,三相电流反而开始震荡。那会儿我的第一反应就是&…

2026/11/13 5:13:25 阅读更多 →
C++核心知识点:从内存管理到STL的实战指南

C++核心知识点:从内存管理到STL的实战指南

C 这门语言我前前后后折腾了十几年,用它写过嵌入式驱动、做过游戏服务端,也搭过基础组件库。每次看到新人一头扎进"C 核心知识点"这个搜索词,我其实挺感慨的——这门语言的难点从来不是语法多,而是知识点之间的耦合太深…

2026/11/12 18:22:26 阅读更多 →
T109滑盖智能锁怎么装?安装调试与故障排查全攻略

T109滑盖智能锁怎么装?安装调试与故障排查全攻略

简介:亚太天能T109滑盖智能锁产品说明书以PDF格式发布,适合智能锁用户、安装人员与售后维修人员阅读。内容围绕T109系列指纹密码刷卡锁展开,先介绍前面板、后面板、锁体、机械钥匙、电池盒盖等部件名称与功能,再给出完整安装步骤&…

2026/11/12 18:22:25 阅读更多 →
LLM知识降熵:从信息垄断到理解权下放

LLM知识降熵:从信息垄断到理解权下放

你有没有过这种经历:翻开源码注释、论文摘要或者一份专业报告,每个字都认识,连在一起却像天书。想找人聊聊,身边要么没人懂,要么懂的懒得跟你解释。后来我试着把同一段内容丢给一个大语言模型,几秒钟之后&a…

2026/11/13 5:13:25 阅读更多 →

日新闻

周新闻

月新闻