[先上一张效果图] :
一,原理:
其实原理很简单:
1. 手机投屏到电脑;
2. 截取投屏画面的题目部分,进行识别,得到题目和三个答案;
3. 将答案按照一定的算法,进行搜索,得出推荐答案;
4. 添加了一些其他辅助功能,比如:浏览器搜索结果展示,关键字高亮,浏览器可点击等;
二,二营长,把我的意大利............... 代码,呈上来,给友军看看 1. 手机投屏:
方式很多,这里只列举几个比较常用,且自己感觉简单易用的:
A.IOS:局域网内,可以利用 iTools 里的苹果录屏大师 (airplay),进行投屏;
B. 安卓:利用连接线,可以用 Totall Control,将安卓手机的画面投到电脑上;而且电脑上还能直接操作手机;
C. 模拟器:一般都是安卓模拟器;可以自行下载并安装;
2. 截取画面中的题目和答案
A. 先设置要截图的区域.
我创建了一个窗体,专门用于设置截图区域,给它取名叫:frmCutter.
原理:在主窗体打开 frmCutter 时,就将 frmCutter 全拼显示.同时截取一张整个屏幕的图片,把它设置成 frmCutter 窗体的背景图片.
这样就能在 frmCutter 上自由地设置了.
主窗体打开 frmCutter 窗体时:
// 新建一个和屏幕大小相同的图片
Bitmap catchBmp = new Bitmap(Screen.AllScreens[0].Bounds.Width, Screen.AllScreens[0].Bounds.Height);
// 创建一个画板,让我们可以在画板上画图
// 这个画板也就是和屏幕大小一样大的图片
// 我们可以通过Graphics这个类在这个空白图片上画图
Graphics g = Graphics.FromImage(catchBmp);
// 把屏幕图片拷贝到我们创建的空白图片 catchBmp中
g.CopyFromScreen(new Point(0, 0), new Point(0, 0), new Size(Screen.AllScreens[0].Bounds.Width, Screen.AllScreens[0].Bounds.Height));
// 创建截图窗体
frmCutter _frmCutter = new frmCutter();
_frmCutter.Tag = this;
// 指示窗体的背景图片为屏幕图片
_frmCutter.BackgroundImage = catchBmp;
_frmCutter.Width = Screen.AllScreens[0].Bounds.Width;
_frmCutter.Height = Screen.AllScreens[0].Bounds.Height;
DialogResult dr = _frmCutter.ShowDialog();
然后再 frmCutter 窗体中,写入几个事件:
//点击鼠标右键时,取消设置
private void frmCutter_MouseClick(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Right)
{
this.DialogResult = DialogResult.OK;
this.Close();
}
}
//点击鼠标左键时,开始画区域图
private void frmCutter_MouseDown(object sender, MouseEventArgs e)
{
// 鼠标左键按下是开始画图,也就是截图
if (e.Button == MouseButtons.Left)
{
// 如果捕捉没有开始
if (!_catchStart && !_catchFinished)
{
_catchStart = true;
// 保存此时鼠标按下坐标
Point newPoint = new Point(e.X, e.Y);
_downPoint = newPoint;
Tools.StartPoint = newPoint;
}
}
}
//鼠标移动时,根据移动的鼠标和点击时的第一个点,绘制矩形
private void frmCutter_MouseMove(object sender, MouseEventArgs e)
{
#region 确保截图开始
if (_catchStart && !_catchFinished)
{
// 新建一个图片对象,让它与屏幕图片相同
Bitmap copyBmp = (Bitmap)Tools.ScreenShots.Clone();
// 获取鼠标按下的坐标
Point newPoint = new Point(_downPoint.X, _downPoint.Y);
// 新建画板和画笔
Graphics g = Graphics.FromImage(copyBmp);
Pen p = new Pen(Color.Red, 1);
// 获取矩形的长宽
int width = Math.Abs(e.X - _downPoint.X);
int height = Math.Abs(e.Y - _downPoint.Y);
if (e.X < _downPoint.X)
{
newPoint.X = e.X;
}
if (e.Y < _downPoint.Y)
{
newPoint.Y = e.Y;
}
_catchRectangle = new Rectangle(newPoint, new Size(width, height));
Tools.CatchRectangle = new Rectangle(newPoint, new Size(width, height));
Tools.CatchRectangleSize = new Size(width, height);
// 将矩形画在画板上
g.DrawRectangle(p, _catchRectangle);
// 释放目前的画板
g.Dispose();
p.Dispose();
// 从当前窗体创建新的画板
Graphics g1 = this.CreateGraphics();
// 将刚才所画的图片画到截图窗体上
// 为什么不直接在当前窗体画图呢?
// 如果自己解决将矩形画在窗体上,会造成图片抖动并且有无数个矩形
// 这样实现也属于二次缓冲技术
g1.DrawImage(copyBmp, new Point(0, 0));
g1.Dispose();
// 释放拷贝图片,防止内存被大量消耗
copyBmp.Dispose();
}
#endregion
}
//鼠标点击后,弹起来时,完成矩形的绘制
private void frmCutter_MouseUp(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
// 如果截图已经开始,鼠标左键弹起设置截图完成
if (_catchStart)
{
Tools.EndPoint = new Point(e.X, e.Y);
_catchStart = false;
_catchFinished = true;
}
}
}
//双击,确定当前选择的设置
private void frmCutter_MouseDoubleClick(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left && _catchFinished)
{
if (this.Tag != null)
{
frmMain _frmMain = (frmMain)this.Tag;
if (_frmMain != null)
{
//_frmMain.btnRead.Focus();
_frmMain.ReadImageResult();
}
}
this.DialogResult = DialogResult.OK;
this.Close();
}
}
B. 设置好截图区域后,每次题目出现时,变对该区域截图:
//截取设置的区域屏幕图片
Bitmap _screenShots = new Bitmap(Screen.AllScreens[0].Bounds.Width, Screen.AllScreens[0].Bounds.Height);
// 创建一个画板,让我们可以在画板上画图
// 这个画板也就是和屏幕大小一样大的图片
// 我们可以通过Graphics这个类在这个空白图片上画图
Graphics g_screenShots = Graphics.FromImage(_screenShots);
// 把屏幕图片拷贝到我们创建的空白图片 CatchBmp中
g_screenShots.CopyFromScreen(new Point(0, 0), new Point(0, 0), new Size(Screen.AllScreens[0].Bounds.Width, Screen.AllScreens[0].Bounds.Height));
//剪切的图片
_catchBmp = new Bitmap(Tools.CatchRectangleSize.Width, Tools.CatchRectangleSize.Height);
Graphics g = Graphics.FromImage(_catchBmp);
g.DrawImage(_screenShots, new Rectangle(0, 0, Tools.CatchRectangleSize.Width, Tools.CatchRectangleSize.Height), Tools.CatchRectangle, GraphicsUnit.Pixel);
g.Dispose();
g_screenShots.Dispose();
//显示图像
this.imgCut.BackgroundImage = (Image) _catchBmp;
C. 将截到的问题和答案图片,用 OCR 识别
比如,我现在设置并截取到了这张图片:
识别图片中的文字,OCR 软件和 API 也不少.以前我用的谷歌 tesseract4.0,安装在本机的,没做词库,识别率一般.
后来发现百度 OCR 每天免费调用 500 次,果断转场!事实证明,正确率还是高很多.
D. 得到识别结果,将识别结果处理后,进行百度搜索:
创建了一个试题实体,后面用起来就方便了:
/// <summary>
/// 试题类
/// </summary>
public class QuestionModel
{
/// <summary>
/// 问题
/// </summary>
public string Question { get; set; }
/// <summary>
/// 答案1
/// </summary>
public string Answer1 { get; set; }
/// <summary>
/// 答案2
/// </summary>
public string Answer2 { get; set; }
/// <summary>
/// 答案3
/// </summary>
public string Answer3 { get; set; }
}
E. 百度搜索,并显示参考答案:
a). 算法搜索:
1. 用题目去百度搜索.在搜索的结果中,查询答案出现的次数.
2. 用题目 + 答案去搜索.得到每个组合的百度结果个数.
然后将上述两种方法,根据权重权衡,用户可以自行决定偏向于哪种结果.
b). 辅助搜索:
右边还放了一个浏览器,可以在得到识别结果的第一时间,呈现出根据题目搜索百度的结果;并且在里面高亮显示 3 个答案关键字.
三,坐等吃鸡!
自动截图,自动识别,自动搜索,自动给出参考答案,自动展现出搜索页面并高亮显示关键字......
多了一系列的辅助功能,想不吃鸡都难啊~
(PS:热烈欢迎广大道友一起交流,指点,大家一起更上一层楼!)
2018.01.25.
来源: https://www.cnblogs.com/donkeysmall/p/8319792.html