如何在emu8086汇编中读取13h模式下的屏幕内容?
实现描摹对比与彩色像素检测的方案
首先得拆解你的核心需求:绘制参考图形(颜色A)→ 用户用颜色B描摹覆盖→ 检测剩余颜色A像素数量→ 基于覆盖率评分。下面分两种思路给你具体实现方案,不管你用Python、Unity还是网页开发栈,都能找到适配的方法:
一、直接检测屏幕彩色像素的方法
这种方法适合不需要精确控制画布的场景,直接读取指定区域的屏幕像素进行统计:
1. Python 快速原型实现
用pyautogui或Pillow库就能轻松完成屏幕抓取与像素统计:
import pyautogui from PIL import Image # 定义画布的坐标范围(避免统计屏幕其他区域) canvas_x1, canvas_y1 = 100, 100 # 画布左上角坐标 canvas_x2, canvas_y2 = 800, 600 # 画布右下角坐标 canvas_region = (canvas_x1, canvas_y1, canvas_x2 - canvas_x1, canvas_y2 - canvas_y1) # 抓取画布区域截图 screenshot = pyautogui.screenshot(region=canvas_region) # 定义颜色A的RGB值(示例为纯红色) color_a = (255, 0, 0) remaining_a_count = 0 width, height = screenshot.size # 遍历像素统计(添加容差避免颜色偏差) for x in range(width): for y in range(height): r, g, b = screenshot.getpixel((x, y)) if abs(r - color_a[0]) < 10 and abs(g - color_a[1]) < 10 and abs(b - color_a[2]) < 10: remaining_a_count += 1 print(f"剩余未覆盖的颜色A像素数:{remaining_a_count}") # 假设你提前知道原始颜色A总像素数,直接计算评分 original_a_count = 50000 # 示例值,可通过提前统计参考图获取 score = ((original_a_count - remaining_a_count) / original_a_count) * 100 print(f"用户描摹评分:{score:.2f}分")
提示:高DPI屏幕下注意坐标缩放问题,pyautogui默认会适配,但手动计算坐标时要提前做转换。
2. Unity 游戏场景实现
在Unity里可以直接读取画布的RenderTexture或Texture2D像素,精度更高:
using UnityEngine; public class TraceScoreCalculator : MonoBehaviour { public Texture2D referenceImage; // 预先生成的颜色A参考图 public RenderTexture canvasRenderTex; // 用户描摹的画布RenderTexture public void CalculateScore() { // 从RenderTexture读取像素数据 Texture2D canvasTex = new Texture2D(canvasRenderTex.width, canvasRenderTex.height); RenderTexture.active = canvasRenderTex; canvasTex.ReadPixels(new Rect(0, 0, canvasRenderTex.width, canvasRenderTex.height), 0, 0); canvasTex.Apply(); Color colorA = referenceImage.GetPixel(0, 0); // 取参考图第一个像素作为颜色A基准 int originalACount = 0; int remainingACount = 0; // 遍历参考图和画布的对应像素 for (int x = 0; x < referenceImage.width; x++) { for (int y = 0; y < referenceImage.height; y++) { Color refPixel = referenceImage.GetPixel(x, y); if (ColorUtility.AreColorsClose(refPixel, colorA, 0.1f)) { originalACount++; // 检查用户画布对应位置是否被颜色B覆盖 Color userPixel = canvasTex.GetPixel(x, y); // 这里假设颜色B是纯绿色,同样加容差判断 if (!ColorUtility.AreColorsClose(userPixel, Color.green, 0.1f)) { remainingACount++; } } } } float score = ((float)(originalACount - remainingACount) / originalACount) * 100; Debug.Log($"用户描摹评分:{score:F2}分"); } }
Unity自带的ColorUtility.AreColorsClose可以帮你轻松处理颜色容差,完美应对抗锯齿或绘制误差。
二、更精准的内存级描摹对比方案(不依赖屏幕抓取)
如果担心屏幕抓取的性能或精度问题,推荐直接在内存中对比画布数据,完全不受屏幕状态影响:
1. HTML5+JS 网页场景实现
把颜色A的参考图放在底层Canvas,用户在顶层Canvas描摹,直接对比两个Canvas的像素数据:
// 获取页面上的参考画布和用户描摹画布 const refCanvas = document.getElementById('reference-canvas'); const userCanvas = document.getElementById('user-canvas'); const refCtx = refCanvas.getContext('2d'); const userCtx = userCanvas.getContext('2d'); function getTraceScore() { const refData = refCtx.getImageData(0, 0, refCanvas.width, refCanvas.height).data; const userData = userCtx.getImageData(0, 0, userCanvas.width, userCanvas.height).data; let originalACount = 0; let remainingACount = 0; // 遍历像素(每4个元素代表一个RGBA像素) for (let i = 0; i < refData.length; i += 4) { // 判断参考图当前像素是否为颜色A(示例为红色) const isColorA = refData[i] === 255 && refData[i+1] === 0 && refData[i+2] === 0; if (isColorA) { originalACount++; // 判断用户画布对应位置是否被颜色B(示例为绿色)覆盖 const isCovered = userData[i] === 0 && userData[i+1] === 255 && userData[i+2] === 0; if (!isCovered) { remainingACount++; } } } const score = ((originalACount - remainingACount) / originalACount) * 100; alert(`你的描摹评分:${score.toFixed(2)}分`); }
这种方法完全在内存中运算,不受窗口缩放、屏幕分辨率影响,是精度最高的方案。
2. 掩码式对比(性能优化方案)
预先为颜色A的图形生成一个像素掩码,记录所有颜色A像素的坐标位置。用户描摹时,每绘制一个颜色B像素就检查是否在掩码范围内,若是则标记为已覆盖。最后统计未覆盖的掩码像素数量即可。
这种方法不需要遍历所有画布像素,只跟踪掩码内的目标像素,性能远高于全量遍历,尤其适合大尺寸画布。
三、关键注意事项
- 颜色容差:绝对的RGB值相等判断很容易出错,一定要给合理的容差范围(比如RGB各通道差值小于10),应对抗锯齿、绘制偏差等情况。
- 区域限制:只统计画布范围内的像素,避免屏幕上的UI按钮、状态栏等无关元素干扰结果。
- 性能优化:大画布场景下,全量像素遍历会比较慢,可以用分块处理、多线程(Python用
multiprocessing,Unity用协程)来提升速度。
内容的提问来源于stack exchange,提问作者Armando Herrera
相关产品推荐
相关产品推荐

