用linux强化window cmd

介绍 Gow,一种轻量级解决方案,为 Windows 用户提供常见的 Linux 命令,提高开发效率。包括如何安装 Gow 和其提供的命令列表。

目标人群:在window下工作,需要cmd,熟悉linux的码工。

 

linux有大量优秀的命令,可以提供工作效率。

要在window下使用,方法有:

1) 虚拟机 vmware等

2) 移植   cygwin 等

 

这里介绍的是,绿色小体积的解决办法,即少量linux命令。

http://github.com/bmatzelle/gow/

http://github.com/bmatzelle/gow/downloads

当前版本 Gow-0.4.0.exe  2010-07-25  5.3MB

 

提供的好处有

1. 在注册表添加 “Command Prompt Here”, 这样可以在目录上右键打开控制台。

 相当于注册表
Windows Registry Editor Version 5.00

[HKEY_CLASSES_ROOT\Directory\shell\CmdHere]
@="CMD &Prompt Here"

[HKEY_CLASSES_ROOT\Directory\shell\CmdHere\command]
@="cmd.exe /k cd \"%1\""
 

2. 常用 {linux command}.exe

 例如
agrep, ansi2knr, basename, bash, bc, bison, bunzip2, bzip2,
bzip2recover, cat, chgrp, chmod, chown, cksum, cmp, comm, compress, cp,
csplit, curl, cut, cvs, dc, dd, df, diff, diff3, dircolors, dirname,
dos2unix, du, egrep, env, expand, expr, factor, fgrep, flex, fmt, fold,
fsplit, gawk, gclip, gow, gplay, grep, gsar, gunzip, gzip, head, id,
indent, install, join, jwhois, less, lesskey, ln, logname, ls, m4, make,
md5sum, mkdir, mkfifo, mknod, mv, mvdir, ncftp, nl, od, pageant, paste,
patch, pathchk, pclip, plink, pr, printenv, printf, pscp, psftp, putty,
puttygen, pwd, recode, rm, rman, rmdir, scp, sdiff, sed, seq, sftp, sh,
shar, sleep, sort, split, stego, su, sum, sync, tac, tail, tar, tee,
test, touch, tr, type, uname, unexpand, uniq, unix2dos, unrar, unshar,
unzip, uudecode, uuencode, vim, wc, wget, whereis, which, whoami, xargs,
yes, zcat, zip
 (加粗部分,是比较常用的字符处理命令)
# -*- coding: utf-8 -*- import copy from dataclasses import dataclass import av import numpy as np import time import subprocess import cv2 import os import platform from typing import Optional, Tuple, List, Dict, Any import queue import re import logging from core.global_variable import display_queue from root_dir import root_path # 设置日志 logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s') logger = logging.getLogger(__name__) class CaptureCardConnection: def __init__(self, ffmpeg_path: str = None): """ 初始化采集卡连接 参数: ffmpeg_path (str, optional): FFmpeg 可执行文件的完整路径。如果为 None,则尝试使用系统 PATH 中的 ffmpeg。 """ self.container = None self.video_stream = None self.device_name = None self.device_id = None self.connection_status = False self.last_check_time = 0 self.check_interval = 2.0 # 连接状态检查间隔(秒) self.actual_resolution = (0, 0) # 存储实际分辨率 self.ffmpeg_path = ffmpeg_path or "ffmpeg" # 默认使用系统 PATH 中的 ffmpeg self.os_type = platform.system() # 获取操作系统类型 self._initialize_device_format() self.available_devices = [] self.current_frame = None self.last_frame_time = 0 self.frame_rate = 0 self.preview_active = False # 预览窗口状态标志 def _initialize_device_format(self): """根据操作系统初始化设备格式""" if self.os_type == "Windows": self.format = "dshow" self.input_prefix = "video=" elif self.os_type == "Linux": self.format = "v4l2" self.input_prefix = "" elif self.os_type == "Darwin": # macOS self.format = "avfoundation" self.input_prefix = "" else: self.format = "dshow" self.input_prefix = "video=" logger.warning(f"未识别的操作系统 {self.os_type},默认使用 DirectShow 格式") def find_available_devices(self) -> List[Dict[str, str]]: """ 使用 FFmpeg 命令行查找所有可用的视频设备 返回: List[Dict]: 可用设备的信息列表,包含名称和ID """ try: # 验证FFmpeg是否可用 if not self._check_ffmpeg_available(): return [] # 根据操作系统构建不同的命令 if self.os_type == "Windows": cmd = [self.ffmpeg_path, "-hide_banner", "-loglevel", "info", "-list_devices", "true", "-f", self.format, "-i", "dummy"] elif self.os_type == "Linux": # Linux使用v4l2-ctl命令(需要安装v4l-utils) cmd = ["v4l2-ctl", "--list-devices"] elif self.os_type == "Darwin": # macOS使用avfoundation的设备列表 cmd = [self.ffmpeg_path, "-hide_banner", "-loglevel", "info", "-f", self.format, "-list_devices", "true", "-i", "dummy"] else: cmd = [self.ffmpeg_path, "-hide_banner", "-loglevel", "info", "-list_devices", "true", "-f", self.format, "-i", "dummy"] logger.info(f"正在执行设备检测命令: {' '.join(cmd)}") # 设置环境变量,确保输出为UTF-8编码 env = os.environ.copy() env['PYTHONIOENCODING'] = 'utf-8' result = subprocess.run( cmd, capture_output=True, text=True, timeout=15, encoding='utf-8', errors='replace', env=env ) # 显示原始输出用于调试 logger.debug("=== FFmpeg 设备检测原始输出 ===") logger.debug(f"标准输出: {result.stdout}") logger.debug(f"错误输出: {result.stderr}") logger.debug("==============================") # 根据操作系统解析不同的输出 if self.os_type == "Windows": return self._parse_windows_devices(result.stderr) elif self.os_type == "Linux": return self._parse_linux_devices(result.stdout) elif self.os_type == "Darwin": return self._parse_macos_devices(result.stderr) else: return self._parse_windows_devices(result.stderr) except FileNotFoundError: logger.error(f"未找到 FFmpeg 可执行文件。请检查路径: {self.ffmpeg_path}") return [] except subprocess.TimeoutExpired: logger.error("设备枚举超时。请检查设备是否正常连接。") return [] except Exception as e: logger.error(f"查找设备失败: {str(e)}") return [] def _check_ffmpeg_available(self) -> bool: """检查FFmpeg是否可用""" try: subprocess.run( [self.ffmpeg_path, "-version"], capture_output=True, text=True, timeout=5 ) return True except FileNotFoundError: logger.error(f"找不到FFmpeg可执行文件在路径: {self.ffmpeg_path}") return False except Exception as e: logger.error(f"检查FFmpeg可用性失败: {str(e)}") return False def _parse_windows_devices(self, output: str) -> List[Dict[str, str]]: """解析Windows系统的设备列表""" devices = [] lines = output.split('\n') i = 0 while i < len(lines): line = lines[i] print(f"line:{line}") # 检查是否是视频设备行 if "\"" in line and "(video)" in line.lower(): # 提取设备名称 match = re.search(r'\"(.+?)\"', line) if match: device_name = match.group(1) # 检查下一行是否是替代名称 if i + 1 < len(lines) and "Alternative name" in lines[i + 1]: alt_line = lines[i + 1] alt_match = re.search(r'@device_.+', alt_line) if alt_match: device_id = alt_match.group(0) print(f"device_id:{device_id}") # 组合设备名称和ID full_device = f"{device_name} [{device_id}]" devices.append({ 'name': device_name, 'id': device_id, 'full_name': full_device }) i += 1 # 跳过下一行,因为我们已经处理了 i += 1 logger.info(f"找到 {len(devices)} 个可用设备: {[d['full_name'] for d in devices]}") self.available_devices = devices return devices def _parse_linux_devices(self, output: str) -> List[Dict[str, str]]: """解析Linux系统的设备列表""" devices = [] lines = output.split('\n') current_device = None for line in lines: line = line.strip() if not line: continue if not line.startswith('/dev/video'): current_device = line else: if current_device: devices.append({ 'name': current_device, 'id': line, 'full_name': f"{current_device} ({line})" }) current_device = None else: devices.append({ 'name': line, 'id': line, 'full_name': line }) logger.info(f"找到 {len(devices)} 个可用设备") return devices def _parse_macos_devices(self, output: str) -> List[Dict[str, str]]: """解析macOS系统的设备列表""" devices = [] lines = output.split('\n') in_video_section = False for line in lines: if "AVFoundation video devices" in line: in_video_section = True continue if "AVFoundation audio devices" in line: in_video_section = False continue if in_video_section and ":" in line: # 提取设备名称 parts = line.split(':', 1) if len(parts) >= 2: device_id = parts[0].strip() device_name = parts[1].strip().strip('"') devices.append({ 'name': device_name, 'id': device_id, 'full_name': f"{device_name} (ID: {device_id})" }) logger.info(f"找到 {len(devices)} 个可用设备") return devices def connect(self, device_index: int, resolution: Optional[Tuple[int, int]] = None) -> bool: """ 连接到指定的采集卡设备 参数: device_index (int): 设备索引(从0开始) resolution (Optional[Tuple[int, int]]): 可选的分辨率设置 (宽度, 高度) 返回: bool: 连接是否成功 """ # 新增:先检查设备列表是否为空 if not self.available_devices: logger.error("没有可用设备,无法连接") return False # 如果已经连接,先断开 if self.container is not None: self.disconnect() # 检查设备索引是否有效 if device_index < 0 or device_index >= len(self.available_devices): logger.error(f"设备索引 {device_index} 无效,可用设备数量: {len(self.available_devices)}") return False device_info = self.available_devices[device_index] device_name = device_info['name'] device_id = device_info['id'] print(f"设备信息:") try: # 构建设备选项 options = {} # 添加分辨率设置(如果指定) if resolution: options['video_size'] = f"{resolution[0]}x{resolution[1]}" options['framerate'] = '30' # 设置帧率 input_str = rf"video={device_id}" # new_text = input_str.replace(f"\",'/') # 或者直接构造完整字符串 # input_str = r'video=@device_pnp_\\?\usb#vid_345f&pid_2130&mi_00#7&1346e323&0&0000#{65e8773d-8f56-11d0-a3b9-00a0c9223196}\global' logger.info(f"尝试连接设备: {device_name}") logger.info(f"输入字符串: {input_str}") logger.info(f"格式: {self.format}") logger.info(f"选项: {options}") # 使用设备输入字符串打开设备 self.container = av.open(file=copy.deepcopy(input_str), format=self.format, options=options) # 查找视频流 self.video_stream = None for stream in self.container.streams: if stream.type == 'video': self.video_stream = stream break if self.video_stream is None: logger.error("未找到视频流") self.disconnect() return False # 获取实际分辨率 self.actual_resolution = ( self.video_stream.width, self.video_stream.height ) self.device_name = device_name self.device_id = device_id self.connection_status = True self.last_check_time = time.time() logger.info(f"已成功连接到设备: {device_name}") logger.info(f"实际分辨率: {self.actual_resolution[0]}x{self.actual_resolution[1]}") return True except Exception as e: logger.error(f"连接设备失败: {str(e)}") self.disconnect() return False def disconnect(self): """断开与采集卡的连接""" if self.container is not None: try: self.container.close() except Exception as e: logger.error(f"关闭连接时出错: {str(e)}") finally: self.container = None self.video_stream = None self.device_name = None self.device_id = None self.connection_status = False self.actual_resolution = (0, 0) logger.info("已断开采集卡连接") def is_connected(self) -> bool: """ 检查采集卡是否仍然连接 返回: bool: 连接状态 """ current_time = time.time() # 避免过于频繁地检查连接状态 if current_time - self.last_check_time < self.check_interval: return self.connection_status self.last_check_time = current_time # 如果未连接,直接返回False if not self.connection_status or self.container is None: return False # 尝试读取一帧来验证连接 try: # 使用非阻塞方式检查连接状态 frame = self.capture(blocking=False) if frame is not None: self.connection_status = True return True else: self.connection_status = False return False except Exception as e: logger.error(f"检查连接状态失败: {str(e)}") self.connection_status = False return False def get_connection_info(self) -> Optional[dict]: """ 获取连接信息 返回: Optional[dict]: 连接信息字典,包含设备名称、分辨率等 """ if not self.is_connected() or self.container is None: return None return { 'device_name': self.device_name, 'device_id': self.device_id, 'resolution': self.actual_resolution, 'backend': f'{self.format} via FFmpeg', 'os': self.os_type } def capture(self, blocking: bool = True) -> Optional[np.ndarray]: """ 捕获单帧图像 参数: blocking (bool): 是否阻塞直到获取到帧 返回: Optional[np.ndarray]: 捕获的帧图像 (OpenCV 格式),如果失败则返回None """ if not self.is_connected() or self.container is None: return None try: # 从视频流中读取帧 for frame in self.container.decode(video=0): # 将帧转换为 numpy 数组 (OpenCV 格式) frame_array = frame.to_ndarray(format='bgr24') # 更新帧率和时间戳 current_time = time.time() if self.last_frame_time > 0: self.frame_rate = 0.9 * self.frame_rate + 0.1 / (current_time - self.last_frame_time) self.last_frame_time = current_time # 根据实际分辨率调整裁剪区域 height, width = frame_array.shape[:2] # 如果分辨率太小,直接返回整个帧 if width < 1067 or height < 600: self.current_frame = frame_array return frame_array # 如果分辨率足够大,进行裁剪 frame1 = frame_array[0:600, 0:1067] self.current_frame = frame1 # 为展示线程准备缩小版本 if not display_queue.full(): display_frame = cv2.resize(frame1, (356, 200)) display_queue.put(display_frame) return frame1 # 如果没有获取到帧 if not blocking: return None except Exception as e: logger.error(f"捕获帧失败: {str(e)}") return None def start_preview(self, window_name: str = "Capture Card Preview", duration: float = 5.0) -> bool: """ 启动预览窗口显示采集卡画面 参数: window_name (str): 窗口名称 duration (float): 预览持续时间(秒),0表示无限 返回: bool: 预览是否成功启动 """ if not self.is_connected(): logger.error("无法启动预览:未连接到设备") return False try: self.preview_active = True cv2.namedWindow(window_name, cv2.WINDOW_NORMAL) frame_count = 0 start_time = time.time() while self.preview_active: if duration > 0 and time.time() - start_time > duration: break if not self.is_connected(): logger.error("连接已断开") break # 捕获一帧 frame = self.capture() if frame is not None: frame_count += 1 # 计算帧率 elapsed_time = time.time() - start_time if elapsed_time > 0: fps = frame_count / elapsed_time cv2.putText(frame, f"FPS: {fps:.1f}", (10, 30), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 255, 0), 2) # 显示帧 cv2.imshow(window_name, frame) # 按 'q' 或 ESC 退出 key = cv2.waitKey(1) & 0xFF if key == ord('q') or key == 27: # 27 is ESC break else: logger.warning("未能捕获到帧") time.sleep(0.1) # 避免CPU占用过高 cv2.destroyWindow(window_name) self.preview_active = False return True except Exception as e: logger.error(f"预览过程中发生错误: {str(e)}") cv2.destroyAllWindows() self.preview_active = False return False def stop_preview(self): """停止预览""" self.preview_active = False def __del__(self): """析构函数,确保资源被释放""" self.disconnect() # 使用示例 if __name__ == "__main__": # 获取操作系统信息 os_type = platform.system() print(f"操作系统: {os_type}") # 根据操作系统设置默认FFmpeg路径 if os_type == "Windows": default_ffmpeg_path = r"C:\Users\Administrator\Desktop\automatic-painting\ffmpeg\bin\ffmpeg.exe" elif os_type == "Linux": default_ffmpeg_path = "ffmpeg" # 通常在PATH中 elif os_type == "Darwin": default_ffmpeg_path = "/usr/local/bin/ffmpeg" # macOS常见路径 else: default_ffmpeg_path = "ffmpeg" # 创建采集卡连接实例 capture_card = CaptureCardConnection(ffmpeg_path=default_ffmpeg_path) # 查找可用设备 print("正在查找可用视频设备...") devices = capture_card.find_available_devices() print(f"find_available_devices 返回: {devices}") # 新增打印 if devices: print(f"找到 {len(devices)} 个可用设备:") for i, device in enumerate(devices, 1): print(f" {i}. {device['full_name']}") # 尝试连接第一个设备 if capture_card.connect(0, (1920, 1080)): print(f"成功连接到设备: {devices[0]['name']}") # 启动5秒预览 capture_card.start_preview(duration=5) # 获取连接信息 info = capture_card.get_connection_info() if info: print(f"设备信息:") print(f" 名称: {info['device_name']}") print(f" ID: {info['device_id']}") print(f" 分辨率: {info['resolution'][0]}x{info['resolution'][1]}") print(f" 后端: {info['backend']}") # 断开连接 capture_card.disconnect() else: print(f"无法连接到设备: {devices[0]['name']}") else: print("未找到可用视频设备") print("请检查:") print("1. FFmpeg 路径是否正确") print("2. 采集卡是否已正确连接") print("3. 设备驱动程序是否已安装") print("4. 是否有足够的权限访问设备(尝试以管理员身份运行)") 帮我改下,还是用设备id 因为有多个同名称设备
最新发布
09-15
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值