新闻详情

新闻详情

首页 / 资讯中心 / 详情

Python OpenCV火车票识别实战:从图像预处理到OCR字段提取

发布时间:2026/9/28 2:01:57来源:尧图网络
Python OpenCV火车票识别实战:从图像预处理到OCR字段提取
简介这是一份基于Python与OpenCV的火车票识别系统项目适合计算机视觉初学者与Python开发者用于学习图像预处理、边缘检测、轮廓分析及OCR文字识别在票证场景中的综合应用。项目共13个文件核心为2个Python脚本搭配8张火车票样本图片、1份说明文档及json配置压缩包仅340KB轻量易部署。已有159人学习浏览。项目内提供OCR识别脚本与主识别程序配合车站名、票价、车次等定位演示图可直观看到从灰度化、直方图均衡化、阈值分割到Canny边缘检测、findContours轮廓提取的完整流程还结合txt说明与json配置梳理了识别思路与参数设置便于对照调试。代码中涉及高斯滤波去噪、形态学操作等图像增强手段可辅助理解真实票证场景下的文字定位与识别难点。整体结构清晰适合毕设选题、课设实践或入门计算机视觉项目参考。1. 打开这个压缩包之前先想清楚火车票识别到底在解决什么问题把一张手机拍歪的火车票变成结构化文本是典型的图像处理入门项目。它不追求把人脸识别那种级别的大模型搬上身而是把 OpenCV 的看家本领——灰度化、二值化、形态学操作、轮廓分析——按顺序走一遍再用 OCR 把像素转成字符。网上这类「基于 Python 的 OpenCV 的火车票识别系统.zip」之所以多是因为链路完整、效果直观输入一张图输出车次、日期、座位号、票价刚好覆盖新手学 OpenCV 图像处理项目必备的全部环节。适合谁有 Python 基础但没碰过 OpenCV 的人想找一个能跑通、能改、能讲清楚原理的项目以及被报销台账烦到想写脚本的普通上班族。这套流程不依赖 GPU不依赖深度学习框架一张车票图上跑完不到两秒。接下来按一条真实落地路径拆先预处理把票面洗干净再定位文字块再做 OCR 和字段提取最后讲我踩过的坑。2. 图像预处理灰度化、二值化与降噪的参数取舍火车票识别第一步不是急着调 OCR而是把图像处理干净。手机拍出来的票面通常有背景阴影、折痕、反光直接喂给识别引擎准确率会惨不忍睹。这个阶段的目标只有一个让文字区域和背景的对比度足够大同时把干扰像素压下去。2.1 读图与颜色空间转换为什么第一步是 BGR 转灰度OpenCV 读进来的图是 BGR 三通道每个像素由蓝、绿、红三个值组成。火车票上除了黑色印刷体文字还有红色印章、蓝色底纹、黄色边框直接对三通道做二值化颜色信息反而会干扰阈值判断。常见做法是先转灰度把亮度信息单独拎出来。import cv2 import numpy as np # 读图时直接转灰度减少一次内存拷贝 img cv2.imread(ticket.jpg) gray cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) # 轻度高斯模糊抑制传感器噪点 blur cv2.GaussianBlur(gray, (3, 3), 0) cv2.imwrite(01_gray.jpg, blur)这里GaussianBlur的核大小(3, 3)是刻意选小的。核越大去噪越强但文字笔画边缘也会被抹糊。火车票印刷体字号在 10 到 20 像素左右用 3 或 5 的核就够了。sigmaX传 0 表示让 OpenCV 根据核大小自动计算标准差日常处理不需要手调。如果票面噪点特别多可以换成(5, 5)但后续二值化时 C 值要相应调大否则细笔画容易断。2.2 二值化的坑固定阈值还是自适应阈值灰度图是 0 到 255 的连续亮度二值化要把它们映射成 0 和 255 两类。最简单的是cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY)全局阈值 127。问题在于火车票照片常常一半亮一半暗——手机闪光灯打上去票面左上角过曝右下角阴影重。全局阈值在这种场景下会直接翻车要么暗部文字融进背景要么亮部背景被当成文字。自适应阈值才是正解它按每个像素周围的局部窗口算阈值不同区域用不同标准。# 自适应阈值blockSize 必须是奇数C 是偏差常数 thresh cv2.adaptiveThreshold( blur, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY, 15, # 局部窗口 15x15 10 # 均值减去 10 作为阈值 ) cv2.imwrite(02_thresh.jpg, thresh)blockSize是核心参数它划定每个像素参考的邻域范围。窗口太小一块小阴影就能让整个区域阈值失效窗口太大又接近全局阈值失去自适应的意义。对 300dpi 的火车票扫描图15到25之间比较稳。C是阈值偏差最终阈值等于局部均值减去 CC 越大判定为文字的前景像素越少。我有一次票面折痕特别重把 C 从 10 调到 18折痕阴影才没被当成文字框出来。调试时一定把每一阶段的中间结果imwrite出来看一遍。灰度图、模糊图、二值图各存一张肉眼确认文字是否连续、背景是否干净比反复调 OCR 参数快得多。2.3 形态学降噪开运算为什么能拆掉孤立噪点自适应阈值输出里常有一条条细小的噪点带尤其是票面边缘的磨损痕迹。这时候上形态学操作比再换滤波器更直接。形态学腐蚀会把前景像素缩小一圈连成片的文字只是变瘦孤立噪点直接消失膨胀再把文字恢复原状。kernel cv2.getStructuringElement(cv2.MORPH_RECT, (3, 3)) opening cv2.morphologyEx(thresh, cv2.MORPH_OPEN, kernel, iterations1) cv2.imwrite(03_opening.jpg, opening)MORPH_OPEN是先腐蚀后膨胀的组合操作专门处理「前景里有小白点」的情况。核形状选矩形MORPH_RECT是因为印刷体文字横竖笔画多矩形核能更完整保留字形如果文字是斜体可以换MORPH_ELLIPSE避免把斜笔画削掉。iterations1就够了跑两轮会明显把文字变瘦后续 OCR 反而更难认出。这一步做完票面上应该只剩清晰的黑色文字、线条和印章轮廓。如果开运算后还有大面积黑块说明二值化时 C 值太小把浅色底纹也当成前景了需要回到上一步调参数。预处理环节的规则就一条让 OCR 的输入尽量接近「白纸黑字」。3. 定位文字区域把像素聚成块把斜票面拉正预处理只是把票面变干净OCR 引擎还不该直接跑整个图。火车票上有零散的红章、二维码、广告语全图识别会让 OCR 输出一堆乱码影响后续字段提取。所以要先帮 OCR 圈出「哪里是正经文字」。3.1 用形态学闭运算把文字行粘成整块文字是一行一行排列的每个字之间有几像素空隙。如果直接提取轮廓会把每个字甚至每个笔画分开。常见做法是先用横向的核做膨胀把同一行的字连成一整块下一步再按块取外接框。这是「opencv 检测直线」思路的近亲——本质都是利用形态学操作在特定方向上合并像素。# 横向长核把一行内的文字粘在一起 kernel_h cv2.getStructuringElement(cv2.MORPH_RECT, (25, 5)) connected cv2.morphologyEx(opening, cv2.MORPH_CLOSE, kernel_h, iterations2) cv2.imwrite(04_connected.jpg, connected)(25, 5)的意思是核宽 25 像素、高 5 像素。横向 25 像素正好覆盖一个字的宽度加字间距膨胀后同一行的字会连起来竖向只有 5 像素避免把上下两行文字也粘成一片。MORPH_CLOSE是先膨胀后腐蚀适合把断裂的前景区域缝合。火车票打印质量差时可以先MORPH_DILATE两轮再MORPH_CLOSE效果更稳代价是行块会稍微膨胀轮廓框偏大一些。3.2 轮廓提取与筛选contourArea 的阈值怎么定连成块之后用findContours提取外轮廓。这一步有个坑不同 OpenCV 版本返回值不一样。4.5 以上版本返回两个值(contours, hierarchy)老代码里写contours, hierarchy cv2.findContours(...)没问题但如果是 4.x 之前的老教程可能是_, contours, hierarchy ...三个值的写法直接复制会报错。contours, _ cv2.findContours(connected, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) boxes [] for cnt in contours: area cv2.contourArea(cnt) if area 500: continue # 过滤掉小噪点块 rect cv2.minAreaRect(cnt) # 旋转外接矩形 box cv2.boxPoints(rect) # 拿到四个顶点 box np.int0(box) # 过滤掉太扁或太细的条状块 w rect[1][0] h rect[1][1] if min(w, h) 10 or max(w, h) 20: continue boxes.append(box) # 按 y 坐标排序后面透视变换要用 boxes.sort(keylambda b: cv2.boundingRect(b)[1])area 500这个阈值是实践拍出来的火车票上最小的一行说明文字面积也在 800 像素以上500 以下的基本是折痕和噪点留下的碎块。图片分辨率不同要按比例缩放比如 4K 图上可以提到 2000。用minAreaRect而不是直接cv2.boundingRect核心原因是手机拍出来的票面大概率是歪的轴对齐框会把相邻行的文字也圈进来旋转框才能贴合实际文字行的角度。3.3 透视矫正把倾斜的矩形拉回正视角拿到票面的四个角点后用透视变换把整张票拉正。这一步直接决定 OCR 能不能按行读对——倾斜超过 15 度的文字行Tesseract 的识别率会掉一半以上。def order_points(pts): 把四个角点按 左上-右上-右下-左下 重新排序 rect np.zeros((4, 2), dtypefloat32) s pts.sum(axis1) rect[0] pts[np.argmin(s)] # 左上角和最小 rect[2] pts[np.argmax(s)] # 右下角和最大 diff np.diff(pts, axis1) rect[1] pts[np.argmin(diff)] # 右上角 diff 最小 rect[3] pts[np.argmax(diff)] # 左下角 diff 最大 return rect if len(boxes) 1: # 用面积最大的轮廓作为票面主体 biggest max(boxes, keylambda b: cv2.contourArea(b)) src_pts order_points(biggest.reshape(4, 2)) # 目标尺寸按实际宽高比算 (tl, tr, br, bl) src_pts widthA np.linalg.norm(br - bl) widthB np.linalg.norm(tr - tl) maxWidth max(int(widthA), int(widthB)) heightA np.linalg.norm(tr - br) heightB np.linalg.norm(tl - bl) maxHeight max(int(heightA), int(heightB)) dst np.array([ [0, 0], [maxWidth - 1, 0], [maxWidth - 1, maxHeight - 1], [0, maxHeight - 1] ], dtypefloat32) M cv2.getPerspectiveTransform(src_pts, dst) warped cv2.warpPerspective(img, M, (maxWidth, maxHeight)) cv2.imwrite(05_warped.jpg, warped)order_points这种排序逻辑是固定套路四角点坐标求和最小的是左上最大的是右下坐标差最小的是右上最大的是左下。直接用不需要改。目标尺寸取变换前后两条边的大值防止文字被等比压缩变形。warpPerspective的输出分辨率尽量保持原图尺度如果票面文字太小可以在这里把目标尺寸放大 1.5 倍OCR 对小字号的识别率会明显提升。到这一步你已经把「一张歪照片」变成了「一张正放的票面」。如果拉正后的图里文字行还有肉眼可见的倾斜是角点排序或轮廓合并出了问题回头检查boxes里是否混入了非票面的噪点轮廓。4. OCR 识别与字段提取怎么把文字流变成结构化数据图像处理到这里剩下的事情是把拉正的票面交给 OCR。这是最容易产生挫败感的环节明明图很干净识别出来却是乱序的、带空格的、缺字少词的一堆字符串。不是 OCR 不行是没给它正确的模式也没做位置排序。4.1 Tesseract 与 PaddleOCR火车票场景该选谁排第一的永远是 Tesseract原因很务实pip install pytesseract三行就能用语言包chi_sim简体中文官方直接发不依赖深度学习框架。火车票上的关键字段——车次、日期、座位号——以数字和少量汉字为主Tesseract 的识别精度够用。PaddleOCR 对复杂版式和彩色印章的鲁棒性更好但它拉起的依赖PaddlePaddle足有几百 MB对只想跑通项目的人来说太重了。另外 Tesseract 支持输出每个词的坐标框这在后面按行重组时是刚需。PaddleOCR 也能输出坐标但安装和模型下载的步骤会让项目失去「十分钟跑通」的轻快感。火车票这种字段位置相对固定的场景选 Tesseract 是性价比最高的路线。4.2 用 image_to_data 拿坐标别用 image_to_string 一把梭新手最容易直接image_to_string一口气吐出所有文字然后对着乱序文本发呆。正确做法是用image_to_data它返回每个词的文本、置信度、边界盒坐标。有了坐标才能按「先按行分组、再按列排序」的方式复原阅读顺序。import pytesseract from pytesseract import Output from collections import defaultdict # 指定中文语言包和单行识字模式 data pytesseract.image_to_data( warped, langchi_sim, config--psm 6, # 6: 把整块当成一个均匀文本块 output_typeOutput.DICT ) # 按 (block, paragraph, line) 三元组把词分组到同一行 line_map defaultdict(list) for i in range(len(data[text])): text data[text][i].strip() conf float(data[conf][i]) if not text or conf -1 or conf 40: continue group_key ( data[block_num][i], data[par_num][i], data[line_num][i], ) line_map[group_key].append({ text: text, left: data[left][i], top: data[top][i], }) # 每个组内按 x 坐标排序组间按 y 坐标排序 ordered_lines [] for key, items in line_map.items(): items.sort(keylambda it: it[left]) line_text .join(it[text] for it in items) ordered_lines.append((key[2], items[0][top], line_text)) ordered_lines.sort(keylambda item: (item[1], item[0])) for _, _, line in ordered_lines: print(line)config--psm 6意味着告诉 Tesseract「这些文字是排版整齐的段落」对票据类文本最稳。--psm 3是全自动分段适合页面--psm 7是单行文本--psm 11是无序文本适合从角落找零散数字。火车票这种上下结构清晰的票面--psm 6几乎不会错。conf 40的过滤阈值不是拍脑袋印刷体汉字 Tesseract 的置信度普遍在 60 以上低于 40 的基本是印章和背景噪点误识别。分组的block_num / par_num / line_num三元组是 Tesseract 内部的版面结构编号。同一物理行的词在这三个编号上完全一致直接拿来做 key 天然完成分行。如果某一行的词被分到两个 block多半是票面上有横线把文字隔开了这时用top坐标做聚类更可靠。4.3 正则提取车次、日期、座位号与票价分行拼接后用正则从每行抽字段。火车票印刷有规律日期是「2024年10月01日」或「2024-10-01」车次是「G1234」「D567」座位是「03车12F号」或「二等座」。正则要写得够宽同时做好去空格处理。import re def parse_ticket(ocr_lines): full_text \n.join(ocr_lines) # 部分 OCR 会在数字中间插入空格 compact re.sub(r\s, , full_text) result {} # 日期兼容 年月日 和 横杠 两种格式 m re.search(r(\d{4})[年\-](\d{1,2})[月\-](\d{1,2})日?, compact) if m: result[date] f{m.group(1)}-{int(m.group(2)):02d}-{int(m.group(3)):02d} # 车次G/D/C/Z/K/T 开头 1到4位数字 m re.search(r([GDCZKQT]\d{1,4})次, compact) if m: result[train_no] m.group(1) # 座位车厢号 座位号 m re.search(r(\d{1,2})车(\d{1,2}[A-F]?)号, compact) if m: result[seat] f{m.group(1)}车{m.group(2)}号 # 票价保留小数点后两位 m re.search(r([¥]?\s?(\d\.\d{2})), compact) if m: result[price] m.group(2) return result正则里的[¥]?同时兼容两种货币符号写法\s?吞掉 OCR 在多字节字符之间塞的空格。日期部分先把年/月/日统一成-分隔并补零方便后续存 Excel。火车票上的「次」字可能被识别成「欠」或「欢」所以车次正则不加次字匹配更稳但那样可能误抓旁边数字。建议先按「G/D/C 字母 数字」这种强前缀去抓。4.4 字段对齐一种更粗糙但更笨的方式如果正则抽出的字段总是漏项还有一个兜底方案根据火车票版式的位置规则硬取。新版火车票的日期通常在右上角车次在日期左侧或下方一行座位号在票面中部靠右。可以在warpPerspective输出上按图像比例裁剪出几个固定区域分别做 OCR再把每个区域的结果单独喂对应正则。这种方式对票面种类固定、扫描位置一致的场景非常稳但换一种票面布局就要重新标坐标可维护性差。我一般先试全局正则失败再用位置裁剪两种配合能覆盖市面上大多数红底蓝底火车票。5. 火车票识别避坑清单五个最容易翻车的细节这个项目跑不通十有八九不是算法问题而是环境和细节配置。以下是我和身边同事反复踩过的坑按「现象 → 原因 → 解决」整理。5.1 import cv2 报 ModulenotFoundError现象import cv2直接报错no module named cv2或者明明刚装完还是找不到。原因装的包不对或装错了 Python 环境。pip install opencv会装到一个不知名的OpenCV包而不是带cv2模块的opencv-python另外用 PyCharm 时右上角解释器选的是 Project 环境但 pip 装到了 base 环境两个环境不互通。解决统一用python -m pip install opencv-python装。python -m前缀保证装到当前解释器对应环境。装完在代码里打印cv2.__version__确认版本号。版本不是说越新越好OpenCV 4.x 对findContours返回值的改动让很多老代码直接崩建议装 4.5 以上避开 3.x 时代的接口写法。5.2 cv2.contourArea 提示未定义标识符现象IDE 里cv2.contourArea(cnt)下面画红线运行报AttributeError: module cv2 has no attribute contourArea。原因OpenCV 的函数名是cv2.contourArea但有人写成cv2.contourarea或cv2.ContourArea——Python 对大小写敏感OpenCV 的命名约定是首字母小写驼峰。还有一种情况是安装了一个被裁剪过的第三方 OpenCV 轮子少编译了部分模块。解决确认函数名大小写再不行就python -c import cv2; print(cv2.__file__)看模块实际路径如果指向 site-packages 里某个怪名目录直接卸载重装opencv-python。顺带说一句findContours返回值的坑也在这个函数附近新版必须写contours, _ cv2.findContours(...)。5.3 自适应阈值后文字断裂成虚线现象二值化图里文字笔画像虚线一样一段一段OCR 识别率暴跌。原因blockSize选的窗口太大把文字笔画和背景算到了同一个局部区域阈值定在了笔画和背景之间笔画边缘被判定为背景。或者GaussianBlur核设太大比如 7x7小字号文字的细笔画被磨平了。解决把blockSize从 15 降到 11C从 10 调到 15——阈值整体抬高笔画判定更激进。如果票面光照特别不均先做cv2.equalizeHist(gray)拉平亮度再二值化。我通常会把二值化后的图放大看单字如果「哎」这种字的竖钩还能完整看到「口」的四个角没黏在一起这一关就过了。5.4 红色印章文字识别成乱码或空白现象票面上红色的「苏州」印章、红色票价数字在二值化图里直接消失OCR 完全读不到。原因灰度化把红色和白色背景按特定权重混成相近的灰。OpenCV 的灰度公式是0.299R 0.587G 0.114B纯红色R255换算后只有大约 76接近白色背景的灰度阈值一卡就没了。解决针对红色内容单独提取。用 HSV 空间把红色像素分离出来再做一次独立的二值化和 OCR。hsv cv2.cvtColor(warped, cv2.COLOR_BGR2HSV) # 红色的色相 H 大致在 0-10 和 170-180 两段 lower1 np.array([0, 80, 80]) upper1 np.array([10, 255, 255]) lower2 np.array([170, 80, 80]) upper2 np.array([180, 255, 255]) mask1 cv2.inRange(hsv, lower1, upper1) mask2 cv2.inRange(hsv, lower2, upper2) red_mask cv2.bitwise_or(mask1, mask2) # 在红色蒙版上跑 OCR单独拿红色信息 red_text pytesseract.image_to_string(red_mask, langchi_sim, config--psm 6)S和V下限设为 80是为了避开灰尘和浅粉底纹。这两个参数偏保守如果印章颜色深可以降到 50浅了容易把肤色、底色也拉进来。红字识别单独跑一遍再和黑字结果合并票面的信息覆盖率会好很多。5.5 Tesseract 中文识别率低连常见字也错现象langchi_sim后中文依然大片乱码比如「闸机」输出成「闽机」。原因最常见的是没装简体中文语言包。Windows 上 pytesseract 只装了英文包时langchi_sim会直接报错如果装的是旧版 3.x Tesseract识别用的还是老引擎而非 LSTM 引擎中文字形稍微倾斜就崩。另外--psm 3全自动分段对票据这种结构化文本反而不如--psm 6稳定。解决装语言包。Windows 装tesseract-ocr-w64-setup时勾选 Chinese SimplifiedLinux 上apt install tesseract-ocr-chi-simmacOS 上brew install tesseract-lang。然后确认pytesseract.get_tesseract_version()输出的是 4.x 以上。LSTM 引擎对倾斜文字的容忍度是旧引擎的十倍以上换新版本往往立竿见影。6. 进阶用法置信度过滤、批量跑批与效果自测项目跑通之后别急着收工。把这三件事做完这套代码才真正能交出去用给 OCR 结果加一道置信度闸门、支持批量处理文件名乱糟糟的图片、用抽样方法量化识别准确率。6.1 用置信度做二次校验上一章的conf 40只是粗过滤。更稳的做法是对关键字段单独设更严的阈值日期里出现字母直接判定失败车次号第一位不是G/D/C/Z/K/T直接拒绝。这种规则比单纯调置信度更可靠因为 OCR 的置信度本身有系统偏差——同一个「6」在不同字体下置信度能差 20 个百分点。def validate_field(key, value, conf): rules { date: lambda v: bool(re.match(r^\d{4}-\d{2}-\d{2}$, v)), train_no: lambda v: bool(re.match(r^[GDCZKQT]\d{1,4}$, v)), price: lambda v: bool(re.match(r^\d\.\d{2}$, v)), } if key not in rules: return True ok rules[key](value) if not ok or conf 60: print(f字段校验失败: {key} - {value}, 置信度 {conf}) return False return True6.2 批量跑批把一堆车票图一次性处理成 CSV日常用的不是单张图而是文件夹里几十张报销凭证。写个循环遍历目录把每张图的解析结果累加进列表最后一次性写进 CSV。import glob import csv results [] for img_path in glob.glob(tickets/*.jpg): img cv2.imread(img_path) warped preprocess_and_warp(img) # 前面 2-3 章的封装 lines ocr_lines(warped) # 第 4 章的封装 parsed parse_ticket(lines) parsed[filename] img_path results.append(parsed) with open(output.csv, w, newline, encodingutf-8-sig) as f: writer csv.DictWriter(f, fieldnames[filename, date, train_no, seat, price]) writer.writeheader() writer.writerows(results)utf-8-sig编码是给 Excel 看的——不加sigExcel 会直接把 UTF-8 的 CSV 当成乱码。glob的路径模式注意 Windows 上反斜杠要写成tickets/*.jpg的正斜杠形式Python 在 Windows 下也支持正斜杠省去转义麻烦。6.3 效果自测人工核对找系统偏差最后一步也是最容易被跳过的一步随便抽 10 张图人工把车次、日期、座位、票价填进一张表和脚本输出对比算字段级准确率。准确率低于 95% 的字段回去查是预处理问题还是正则问题——日期错了大概率是二值化把数字 0 和 8 弄混车次错了通常是倾斜矫正没拉正。这个环节不花多少时间但能帮你找到系统性的翻车规律而不是靠一次次跑随机数碰运气。我做这套流程时最深的感触是火车票识别八成的功夫在预处理OCR 反而是最省心的一步。票面干净、拉得正、区域切得准识别率自然上来图没处理好的时候调什么参数都是玄学。把中间结果一张张存下来看比盯着一堆数字猜高效太多。希望这套拆解能帮你少走几趟弯路也欢迎把你在票据识别里踩到的更刁钻的坑拿出来一起琢磨。本文还有配套的精品资源点击获取
网站建设高端定制企业官网
RELATED

相关资讯

更多精彩内容,欢迎继续阅读

较早相关资讯

最新相关资讯

LPDDR5初始化调试指南:从Power Ramp到CA Training的完整链路 2026/9/28 5:03:30

LPDDR5初始化调试指南:从Power Ramp到CA Training的完整链路

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

阅读更多 →
C语言项目实战:用SDL2从零开发神庙逃亡跑酷游戏 2026/9/28 5:03:30

C语言项目实战:用SDL2从零开发神庙逃亡跑酷游戏

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

阅读更多 →
RTP.NET实战笔记:从RTP/RTCP协议到音视频收发的完整拆解 2026/9/28 5:03:30

RTP.NET实战笔记:从RTP/RTCP协议到音视频收发的完整拆解

简介:RTP.NET是一套基于.NET框架实现的RTP(实时传输协议)封装库,面向需要构建VoIP、视频会议、流媒体服务等实时通信应用的.NET开发者。库中提供RTPSession会话管理、RTPParticipant参与者元数据、数据包化、负载类型识别、事件驱…

阅读更多 →
二手房数据爬取实战:绕过反爬获取结构化房源数据 2026/9/28 5:03:30

二手房数据爬取实战:绕过反爬获取结构化房源数据

简介:本资源是一套高分Python毕业设计实战项目,面向计算机/数据科学方向本科生及爬虫初学者,聚焦二手房市场数据采集与可视化分析这一典型应用场景。项目完整实现从网页抓取、数据清洗到多维度图表呈现的全流程,涵盖价格分布、区域…

阅读更多 →
ConvLSTM视频分类实战:端到端时序图像分类落地指南 2026/9/28 5:03:29

ConvLSTM视频分类实战:端到端时序图像分类落地指南

简介:本资源是一份面向深度学习初学者与进阶实践者的 ConvLSTM 模型精简实现代码包,聚焦图像序列建模核心能力,适用于视频预测、动作识别、气象时序图像分析等时空建模任务。压缩包为 rar 格式,仅含 1 个 Python 源文件&#xff0…

阅读更多 →
企业网站模板下载哪里好:5大渠道实测与避坑注意事项 2026/9/28 5:03:23

企业网站模板下载哪里好:5大渠道实测与避坑注意事项

企业网站模板下载哪里好:5大渠道实测与避坑注意事项 你是不是也遇到过这种情况:花大价钱买的企业网站模板,下载下来一看,配色土气、排版僵硬,往公司Logo一放,简直像个“电子废品”。更惨的是,刚把素材换完,手机打开全是乱码,客户点进去转圈半天…

阅读更多 →

今日资讯

本周资讯

本月资讯

看完文章仍有疑问?

联系尧图顾问,获取一对一建站咨询

立即免费咨询 📞 400-888-8888
📞 ✉