根据采集到的数据绘制曲线

在串口编程中会涉及到这样一个问题,就是将采集到的数据以曲线的形式展示出来,大家自然而然会想到采用方便快捷的控件进行编程。编程周期短,完成任务快,但是真实情况来看,控件会实现很多你用不到的功能,实现机制也不可见,这样在功能上会造成浪费,对性能和实现的效果上会有一些不可控,所以在这一类编程中建议自己通过设备上下文自己编写适合自己软件的曲线图。

我要实现的功能如下图:

这是一个在网上下载的例程运行的效果,我中间采用的编程思想大多来源这里,只是针我要实现的功能进行了修改。因为我的程序现在还没进行设备测试,所以这里借用一下这个效果图。

将画图实现的功能封装在一个类里面,在需要画图的时候,便可以实例化一个对象。

下面是详细的实现过程,为防止屏幕闪烁,采用了双缓冲技术。

实现的过程中主要的两问题是:1、为了绘制速度快,不会因为数据的增加而出现绘制越来越慢,最后卡死的现象,这里采用例程中用的方法,将已经画过的图像保存BitMap 中,来了数据直接在map上绘制,然后再复制在屏幕上。2、我的功能中会根据用户操作改变曲线显示的区域大小,这个时候就需要全部重绘,原来map里的曲线就不能再用了,因为大小已经改变了,这时候在OnPaint函数里面实现的功能就是重新绘制坐标轴框图和根据保存的数据进行曲线的绘制。

该类的头文件函数:

 #pragma once

 //用于绘制二维曲线
class CDrawView : public CWnd
{
DECLARE_DYNCREATE(CDrawView) public:
CDrawView();
virtual ~CDrawView();
DECLARE_MESSAGE_MAP() public:
#ifdef _DEBUG
virtual void AssertValid() const;
#ifndef _WIN32_WCE
virtual void Dump(CDumpContext& dc) const;
#endif
#endif public: CPoint m_dCurrentPosition; //current position
CPoint m_dPreviousPosition; //previous position
double m_updateRate;//数据更新率
void setUpdateRate(double updateRate); CList<CPoint,CPoint&> dataList;//用于存储真实数据
CList<CPoint,CPoint&> dataList1;//用于绘图
CList<CPoint,CPoint&> tempDataList;//暂存数据
void InvalidateCtrl();
void SetYRange(double dYLower, double dYUpper, int nYDecimalPlaces);
void SetXRange(int dXLower,int dXUpper,int nXDecimalPlaces);
void SetXUnits(CString string);
void SetYUnits(CString string);
void SetGridColor(COLORREF color);
void SetPlotColor(COLORREF color);
void SetBackgroundColor(COLORREF color);
void SetTitle(CString title);
void AppendPoint(CPoint *newDataList);
void Reset();
void DrawPoint(); //各个部分的颜色
COLORREF m_crBackColor; //backGround color
COLORREF m_crGridColor; //Grid color
COLORREF m_crPlotColor; //data plot color //设备上下文以及与其相关的位图 CDC m_dcGrid;
CDC m_dcPlot;
CBitmap *m_pBitmapOldGrid;
CBitmap *m_pBitmapOldPlot;
CBitmap m_pBitmapGrid;
CBitmap m_pBitmapPlot; //画图区域相关
int m_nHalfShiftPixels;
int m_nPlotShiftPixels;
int m_nClientHeight;
int m_nClientWidth;
int m_nPlotHeight;
int m_nPlotWidth; //坐标轴Y
double m_dYLowerLimit;
double m_dYUpperLimit;
double m_dYRange;
double m_dVerticalFactor; //坐标轴X
int m_dXLowerLimit;
int m_dXUpperLimit;
double m_dXRange;
double m_dHorizontalFactor; //title
CString m_sTitile; CRect m_rectClient;
CRect m_rectPlot;
CPen m_penPlot;
CBrush m_brushBack; int m_nShiftPixels; //amount to shift with each new point
int m_nYDecimal;
int m_nXDecimal; CString m_strXUnitsString;
CString m_strYUnitsString; CString str;
CList<int,int>listOfFogX; afx_msg void OnPaint();
BOOL Create(DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID=NULL);
afx_msg void OnSize(UINT nType, int cx, int cy);
};

该类的实现文件内容:

 // DrawView.cpp : 实现文件
// #include "stdafx.h"
#include "IMU4.h"
#include "DrawView.h"
#include "math.h" // CDrawView IMPLEMENT_DYNCREATE(CDrawView, CWnd) CDrawView::CDrawView()
{
m_nYDecimal = ; m_dPreviousPosition.x = ;
m_dPreviousPosition.y = ; m_dCurrentPosition.x = ;
m_dCurrentPosition.y = ; m_dYLowerLimit = -10.0 ;
m_dYUpperLimit = 10.0 ;
m_dYRange = m_dYUpperLimit - m_dYLowerLimit ; m_dXLowerLimit = ;
m_dXUpperLimit = ;
m_dXRange = m_dXUpperLimit - m_dXLowerLimit; m_dVerticalFactor = (double)m_nPlotHeight / m_dYRange ;
m_dHorizontalFactor = (double)m_nClientWidth / m_dXRange / 100.0; m_nShiftPixels = ;
m_nHalfShiftPixels = m_nShiftPixels/ ;
m_nPlotShiftPixels = m_nShiftPixels + m_nHalfShiftPixels ; m_crBackColor = RGB( , , ) ;
m_crGridColor = RGB( , , ) ;
m_crPlotColor = RGB(, , ) ; m_penPlot.CreatePen(PS_SOLID, , m_crPlotColor) ;
m_brushBack.CreateSolidBrush(m_crBackColor) ; m_strXUnitsString.Format(_T("")) ;
m_strYUnitsString.Format(_T("")) ; m_pBitmapOldGrid = NULL ;
} CDrawView::~CDrawView()
{ } BEGIN_MESSAGE_MAP(CDrawView, CWnd)
ON_WM_MOUSEACTIVATE()
ON_WM_DESTROY()
ON_WM_PAINT()
ON_WM_SIZE()
ON_WM_TIMER()
END_MESSAGE_MAP() #ifdef _DEBUG
void CDrawView::AssertValid() const
{
CWnd::AssertValid();
} #ifndef _WIN32_WCE
void CDrawView::Dump(CDumpContext& dc) const
{
CWnd::Dump(dc);
}
#endif
#endif
void CDrawView::InvalidateCtrl()
{
//用于画坐标轴等信息的函数
int i;
int nCharacters;
int nTopGridPix,nMidGridPix,nBottomGridPix;//分别代表绘图区的三条线(暂定) CPen *oldPen;
CPen solidPen(PS_SOLID,,m_crGridColor);//建立一个画实线的画笔对象
CFont axisFont,yUnitFont,*oldFont;//建立三个字体对象
CString strTemp = _T(""); CClientDC dc(this);
if(m_dcGrid.GetSafeHdc() == NULL)
{
m_dcGrid.CreateCompatibleDC(&dc);
m_pBitmapGrid.CreateCompatibleBitmap(&dc,m_nClientWidth,m_nClientHeight);
m_pBitmapOldGrid = m_dcGrid.SelectObject(&m_pBitmapGrid);
}
m_dcGrid.SetBkColor(m_crBackColor);
m_dcGrid.FillRect(m_rectClient, &m_brushBack) ;
nCharacters = max(abs((int)log10(fabs(m_dYUpperLimit))),abs((int)log10(fabs(m_dYLowerLimit))));
nCharacters = nCharacters + + m_nYDecimal; m_rectPlot.left = m_rectClient.left + * nCharacters;
m_nPlotWidth = m_rectPlot.Width(); //draw the plot rectangle
oldPen = m_dcGrid.SelectObject(&solidPen);
m_dcGrid.MoveTo(m_rectPlot.left,m_rectPlot.top);
m_dcGrid.LineTo(m_rectPlot.right + ,m_rectPlot.top);
m_dcGrid.LineTo(m_rectPlot.right + ,m_rectPlot.bottom + );
m_dcGrid.LineTo(m_rectPlot.left,m_rectPlot.bottom + );
m_dcGrid.LineTo(m_rectPlot.left,m_rectPlot.top); //draw the dotted lines,
//use setPixel instead of a dotted pen - this allows for a
//finer dotted line and a more "" technical "look
nMidGridPix = (m_rectPlot.top + m_rectPlot.bottom) / ;
nTopGridPix = nMidGridPix - m_nPlotHeight / ;
nBottomGridPix = nMidGridPix + m_nPlotHeight / ; for(i = m_rectPlot.left; i < m_rectPlot.right; i+= )
{
m_dcGrid.SetPixel(i,nTopGridPix,m_crGridColor);
m_dcGrid.SetPixel(i,nMidGridPix,m_crGridColor);
m_dcGrid.SetPixel(i,nBottomGridPix,m_crGridColor);
} //create some fonts (horiaontal and vertical )
//use a height of 14 pixels and 300 weight
//(this may need to be adjusted depending on the display ) axisFont.CreateFont (, , , , ,
FALSE, FALSE, , ANSI_CHARSET,
OUT_DEFAULT_PRECIS,
CLIP_DEFAULT_PRECIS,
DEFAULT_QUALITY,
DEFAULT_PITCH|FF_SWISS, _T("Arial"));
yUnitFont.CreateFont (, , , , ,
FALSE, FALSE, , ANSI_CHARSET,
OUT_DEFAULT_PRECIS,
CLIP_DEFAULT_PRECIS,
DEFAULT_QUALITY,
DEFAULT_PITCH|FF_SWISS, _T("Arial")) ; //grab the horizontal font
oldFont = m_dcGrid.SelectObject(&axisFont); //y max
m_dcGrid.SetTextColor(m_crGridColor);
m_dcGrid.SetTextAlign(TA_RIGHT|TA_TOP);
strTemp.Format (_T("%.*lf"),m_nYDecimal, m_dYUpperLimit) ;//*号会被m_nYDecimals取代,表示保留几位小数
m_dcGrid.TextOutW(m_rectPlot.left - ,m_rectPlot.top,strTemp); m_dcGrid.SetTextAlign (TA_LEFT|TA_TOP) ;
m_dcGrid.TextOut (m_rectPlot.left - , m_rectPlot.bottom - ( - m_dYLowerLimit) * m_dVerticalFactor, _T("")) ;
//y min
m_dcGrid.SetTextAlign(TA_RIGHT|TA_BASELINE);
strTemp.Format(_T("%.*lf"),m_nYDecimal,m_dYLowerLimit);
m_dcGrid.TextOutW(m_rectPlot.left - ,m_rectPlot.bottom,strTemp); //x min
m_dcGrid.SetTextAlign (TA_LEFT|TA_TOP) ;
m_dcGrid.TextOut (m_rectPlot.left, m_rectPlot.bottom+, _T("")) ;
//横坐标
for(int i = ;i <= ;i++)
{
m_dcGrid.SetTextAlign(TA_CENTER|TA_TOP);
strTemp.Format(_T("%d"),m_dXUpperLimit * i / );
m_dcGrid.TextOut((m_rectPlot.left + m_nPlotWidth * i / ),m_rectPlot.bottom + , strTemp);
}
// x max
m_dcGrid.SetTextAlign (TA_RIGHT|TA_TOP) ;
strTemp.Format (_T("%d"), m_dXUpperLimit) ;
m_dcGrid.TextOut (m_rectPlot.right, m_rectPlot.bottom+, strTemp) ; // x units
m_dcGrid.SetTextAlign (TA_CENTER|TA_TOP) ;
m_dcGrid.TextOut (m_rectPlot.right - ,
m_rectPlot.bottom+, m_strXUnitsString) ;
//title
m_dcGrid.SetTextAlign (TA_CENTER|TA_TOP) ;
m_dcGrid.TextOut ((m_rectPlot.left+m_rectPlot.right)/,
m_rectPlot.top-, m_sTitile) ; // restore the font
m_dcGrid.SelectObject(oldFont) ;
// y units
oldFont = m_dcGrid.SelectObject(&yUnitFont) ;
m_dcGrid.SetTextAlign (TA_CENTER|TA_BASELINE) ;
m_dcGrid.TextOut ((m_rectClient.left+m_rectPlot.left)/,
(m_rectPlot.bottom+m_rectPlot.top)/, m_strYUnitsString) ;
m_dcGrid.SelectObject(oldFont) ; //创建画曲线的内存DC和兼容Bitmap
if (m_dcPlot.GetSafeHdc() == NULL)
{
m_dcPlot.CreateCompatibleDC(&dc) ;
m_pBitmapPlot.CreateCompatibleBitmap(&dc, m_nClientWidth, m_nClientHeight) ;
m_pBitmapOldPlot = m_dcPlot.SelectObject(&m_pBitmapPlot) ;
}
// make sure the plot bitmap is cleared
m_dcPlot.SetBkColor (m_crBackColor) ;
m_dcPlot.FillRect(m_rectClient, &m_brushBack) ;
} //set title
void CDrawView::SetTitle(CString title)
{
m_sTitile = title;
InvalidateCtrl();
}
void CDrawView::SetYRange(double dYLower, double dYUpper, int nYDecimalPlaces)
{
ASSERT(dYUpper > dYLower) ; m_dYLowerLimit = dYLower ;
m_dYUpperLimit = dYUpper ;
m_nYDecimal = nYDecimalPlaces ;
m_dYRange = m_dYUpperLimit - m_dYLowerLimit ;
m_dVerticalFactor = (double)m_nPlotHeight / m_dYRange ; InvalidateCtrl() ;
} // SetYRange void CDrawView::SetXRange(int dXLower,int dXUpper,int nXDecimalPlaces)
{
ASSERT(dXUpper > dXLower); m_dXLowerLimit = dXLower;
m_dXUpperLimit = dXUpper;
m_nXDecimal = nXDecimalPlaces;
m_dXRange = m_dXUpperLimit - m_dXLowerLimit;
m_dHorizontalFactor = (double)m_nPlotWidth / m_dXRange / 400.0 /** (m_updateRate * 400)*/; InvalidateCtrl();
} void CDrawView::SetXUnits(CString string)
{
m_strXUnitsString = string ;
InvalidateCtrl() ; } // SetXUnits void CDrawView::SetYUnits(CString string)
{
m_strYUnitsString = string ;
InvalidateCtrl() ; } // SetYUnits void CDrawView::SetGridColor(COLORREF color)
{
m_crGridColor = color ;
InvalidateCtrl() ; } // SetGridColor void CDrawView::SetPlotColor(COLORREF color)
{
m_crPlotColor = color ; m_penPlot.DeleteObject() ;
m_penPlot.CreatePen(PS_SOLID, , m_crPlotColor) ;
InvalidateCtrl() ; } // SetPlotColor void CDrawView::SetBackgroundColor(COLORREF color)
{
m_crBackColor = color ; m_brushBack.DeleteObject() ;
m_brushBack.CreateSolidBrush(m_crBackColor) ;
InvalidateCtrl() ; } // SetBackgroundColor void CDrawView::AppendPoint(CPoint *newpPoint)
{
//在plotBitmap上继续画刚接收到的一个数据点,如果一次画本次接收到的所有数据,耗时严重,实时性不强
CPoint dPrevious; dPrevious = m_dCurrentPosition;
m_dCurrentPosition = *newpPoint;
//根据新来的数据点更新纵坐标
if(m_dCurrentPosition.y < m_dYLowerLimit)
{
m_dYLowerLimit = m_dCurrentPosition.y;
}
if(m_dCurrentPosition.y > m_dYUpperLimit)
{
m_dYUpperLimit = m_dCurrentPosition.y;
}
//将数据保存在链表里用于重绘以及后面的参数计算
dataList.AddTail(m_dCurrentPosition);
//在plotBitmap上接着画当前数据点
DrawPoint();
//在界面上显示出来
//在这里要注意CClientDC和CPaintDC的区别,一定要避免在OnPaint函数里直接或间接的用CClientDC,这样会使界面一直重绘,造成假死现象
if(IsWindow(this->m_hWnd))
{
CClientDC dc(this) ; // device context for painting
CDC memDC ; //定义一个内存设备描述表对象(即后备缓冲区)
CBitmap memBitmap ; //定义一个位图对象
CBitmap* oldBitmap ; // bitmap originally found in CMemDC if(dc.GetSafeHdc() != NULL)
{
memDC.CreateCompatibleDC(&dc) ;//建立与屏幕设备描述表(前端缓冲区)兼容的内存设备描述表句柄(后备缓冲区)
memBitmap.CreateCompatibleBitmap(&dc, m_nClientWidth, m_nClientHeight) ;//建立一个与屏幕设备描述表(或者内存设备描述表)兼容的位图
oldBitmap = (CBitmap *)memDC.SelectObject(&memBitmap) ;//只有选入了位图的设备描述表才有地方绘图,画到指定的位图上 if (memDC.GetSafeHdc() != NULL)
{
// first drop the grid on the memory dc
memDC.BitBlt(, , m_nClientWidth, m_nClientHeight,
&m_dcGrid, , , SRCCOPY) ;
// now add the plot on top as a "pattern" via SRCPAINT.
// works well with dark background and a light plot
memDC.BitBlt(, , m_nClientWidth, m_nClientHeight,
&m_dcPlot, , , SRCPAINT) ; //SRCPAINT
// finally send the result to the display
dc.BitBlt(, , m_nClientWidth, m_nClientHeight,
&memDC, , , SRCCOPY) ;
} memDC.SelectObject(oldBitmap) ;
}
}
}
//将当前数据点绘制到plotBitmap上
void CDrawView::DrawPoint()
{
double currX, prevX, currY, prevY ; CPen *oldPen ;
CRect rectCleanUp ; if (m_dcPlot.GetSafeHdc() != NULL)
{ oldPen = m_dcPlot.SelectObject(&m_penPlot) ;
// 移到由prevX和prevY指定的前一个位置
prevX = m_rectPlot.left + m_dPreviousPosition.x * m_dHorizontalFactor;
prevY = m_rectPlot.bottom -
(long)((m_dPreviousPosition.y - m_dYLowerLimit) * m_dVerticalFactor);
m_dcPlot.MoveTo (prevX, prevY); // 画到当前点的位置
currX = m_rectPlot.left + m_dCurrentPosition.x * m_dHorizontalFactor;
currY = m_rectPlot.bottom -
(long)((m_dCurrentPosition.y - m_dYLowerLimit) * m_dVerticalFactor);
m_dcPlot.LineTo (currX, currY); // restore the pen
m_dcPlot.SelectObject(oldPen) ;
// store the current point for connection to the next point
m_dPreviousPosition.x = m_dCurrentPosition.x ;
m_dPreviousPosition.y = m_dCurrentPosition.y;
} } // end DrawPoint
void CDrawView::OnPaint()
{
if(m_dcGrid.GetSafeHdc() != NULL)
{
m_dcGrid.DeleteDC();
m_pBitmapGrid.DeleteObject();
}
if(m_dcPlot.GetSafeHdc() != NULL)
{
m_dcPlot.DeleteDC();
m_pBitmapPlot.DeleteObject();
} InvalidateCtrl(); double pointX,pointY;
CPoint tempPoint;
CPen *oldPen1 ;
//dataList1.RemoveAll();
if(dataList.GetCount() > )
{
//绘图区域大小已经改变,需要重绘
if(m_dcPlot.GetSafeHdc() != NULL )
{
oldPen1 = m_dcPlot.SelectObject(&m_penPlot) ;
POSITION pos1 = dataList.GetHeadPosition(); tempPoint = dataList.GetNext(pos1);
pointX = m_rectPlot.left + tempPoint.x * m_dHorizontalFactor;
pointY = m_rectPlot.bottom -
(long)((tempPoint.y - m_dYLowerLimit) * m_dVerticalFactor);
m_dcPlot.MoveTo(pointX,pointY);
CString str;
str.Format(_T("long is %d"),dataList.GetCount());
//TRACE(str);
for(int i = ; i < dataList.GetCount();i++ )
{
tempPoint = dataList.GetNext(pos1);
pointX = m_rectPlot.left + tempPoint.x * m_dHorizontalFactor;
pointY = m_rectPlot.bottom -
(long)((tempPoint.y - m_dYLowerLimit) * m_dVerticalFactor);
m_dcPlot.LineTo(pointX,pointY);
m_dcPlot.MoveTo(pointX,pointY);
}
m_dcPlot.SelectObject(oldPen1);
}
} if(m_nClientHeight != )
{
CPaintDC dc(this) ; // device context for painting CDC memDC ; //定义一个内存设备描述表对象(即后备缓冲区)
CBitmap memBitmap ; //定义一个位图对象
CBitmap* oldBitmap ; // bitmap originally found in CMemDC memDC.CreateCompatibleDC(&dc) ;//建立与屏幕设备描述表(前端缓冲区)兼容的内存设备描述表句柄(后备缓冲区)
memBitmap.CreateCompatibleBitmap(&dc, m_nClientWidth, m_nClientHeight) ;//建立一个与屏幕设备描述表(或者内存设备描述表)兼容的位图
oldBitmap = (CBitmap *)memDC.SelectObject(&memBitmap) ;//只有选入了位图的设备描述表才有地方绘图,画到指定的位图上 if (memDC.GetSafeHdc() != NULL)
{ //first drop the grid on the memory dc
memDC.BitBlt(, , m_nClientWidth, m_nClientHeight,
&m_dcGrid, , , SRCCOPY) ;
// now add the plot on top as a "pattern" via SRCPAINT.
// works well with dark background and a light plot memDC.BitBlt(, , m_nPlotWidth, m_nPlotHeight,
&m_dcPlot, , , SRCPAINT) ; //SRCPAINT
//finally send the result to the display
dc.BitBlt(, , m_nClientWidth, m_nClientHeight,
&memDC, , , SRCCOPY) ; } memDC.SelectObject(oldBitmap) ;
memDC.DeleteDC();
memBitmap.DeleteObject();
}
} void CDrawView::Reset()
{
InvalidateCtrl() ;
} BOOL CDrawView::Create(DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID)
{
// TODO: 在此添加专用代码和/或调用基类
BOOL result;
static CString className = AfxRegisterWndClass(CS_HREDRAW|CS_VREDRAW);//注册窗口类,返回值包含创建的窗口类的信息
result = CWnd::CreateEx(WS_EX_CLIENTEDGE | WS_EX_STATICEDGE,
className, NULL, dwStyle,
rect.left, rect.top, rect.right-rect.left, rect.bottom-rect.top,
pParentWnd->GetSafeHwnd(), (HMENU)nID) ;
m_dPreviousPosition.x = ;
m_dPreviousPosition.y = ; m_dCurrentPosition.x = ;
m_dCurrentPosition.y = ;
if (result != )
// InvalidateCtrl() ; return result ;
} void CDrawView::OnSize(UINT nType, int cx, int cy)
{
CWnd::OnSize(nType, cx, cy); GetClientRect(&m_rectClient) ;
// set some member variables to avoid multiple function calls
m_nClientHeight = m_rectClient.Height() ;
m_nClientWidth = m_rectClient.Width() ;
// the "left" coordinate and "width" will be modified in
// InvalidateCtrl to be based on the width of the y axis scaling
m_rectPlot.left = ;
m_rectPlot.top = ;
m_rectPlot.right = m_rectClient.right- ;
m_rectPlot.bottom = m_rectClient.bottom- ; // set some member variables to avoid multiple function calls
m_nPlotHeight = m_rectPlot.Height() ;
m_nPlotWidth = m_rectPlot.Width() ; // set the scaling factor for now, this can be adjusted
// in the SetRange functions
m_dVerticalFactor = (double)m_nPlotHeight / m_dYRange ;
m_dHorizontalFactor = (double)m_nClientWidth / m_dXRange /400.0 /** (m_updateRate * 400)*/; }
void CDrawView::setUpdateRate(double updateRate)
{
m_updateRate = updateRate;
}

MFC--根据串口采集的数据借助GDI绘制曲线的更多相关文章

  1. 基于opencv和mfc的摄像头采集代码(GOMFCTemplate2)

            编写带界面的图像处理程序,选择opencv+mfc是一种很好的选择:在读取摄像头数据方面,网上的方法很多,其中shiqiyu的camerads的方法是较好的.       基于现有资料 ...

  2. 基于opencv和mfc的摄像头采集代码(GOMFCTemplate2)持续更新

            编写带界面的图像处理程序,选择opencv+mfc是一种很好的选择:在读取摄像头数据方面,网上的方法很多,其中shiqiyu的camerads的方法是较好的.       基于现有资料 ...

  3. C#串口通信及数据表格存储

    1.开发环境 系统:win10 开发工具:Visual Studio 2017 2.界面设计 串口通信的界面大致如此,在此基础上添加项目所需的调试指令与数据存储功能,界面排布方面可参考其他教程. 3. ...

  4. [转]MFC子线程更改图像数据后更新主窗口图像显示方法

    程序思路是由外部的输入输出控制卡发出采集图像信号,之后相机采集图像得到图像数据指针,接收图像数据指针创建成图像最后显示到MFC对话框应用程序的Picture Control控件上,同时,为了标定相机位 ...

  5. C#+HtmlAgilityPack+XPath带你采集数据(以采集天气数据为例子)

    第一次接触HtmlAgilityPack是在5年前,一些意外,让我从技术部门临时调到销售部门,负责建立一些流程和寻找潜在客户,最后在阿里巴巴找到了很多客户信息,非常全面,刚开始是手动复制到Excel, ...

  6. Gobblin采集kafka数据

    作者:Syn良子 出处:http://www.cnblogs.com/cssdongl 转载请注明出处 找时间记录一下利用Gobblin采集kafka数据的过程,话不多说,进入正题 一.Gobblin ...

  7. 在Linux中如何使用命令进行RS-232串口通信和数据包解析

    文章首发于浩瀚先森博客 1. 获取串口号 在Linux系统中一切皆为文件,所以串口端口号也不例外,都是以设备文件的形式出现.也就是说我们可以用访问文本文件的命令来访问它们. a. 一般串口都是以/de ...

  8. STM32移植RT-Thread后的串口在调试助手上出现:(mq != RT_NULL) assert failed at rt_mq_recv:2085和串口只发送数据不能接收数据问题

    STM32移植RT-Thread后的串口在调试助手上出现:(mq != RT_NULL) assert failed at rt_mq_recv:2085的问题讨论:http://www.rt-thr ...

  9. API例子:用Python驱动Firefox采集网页数据

    1,引言 本文讲解怎样用Python驱动Firefox浏览器写一个简易的网页数据采集器.开源Python即时网络爬虫项目将与Scrapy(基于twisted的异步网络框架)集成,所以本例将使用Scra ...

随机推荐

  1. 微信支付 超时 mysql.event

    $wtime 使用具体timestamp //rand 防推测 $wev = 'ev_gbuy_create_' . trim($winsert_id) . rand(100, 999); $sql ...

  2. stopPropagation(), preventDefault() , return false 事件

    因为有父, 子节点同在, 因为有监听事件和浏览器默认动作之分. 使用 JavaScript 时为了达到预期效果经常需要阻止事件和动作执行. 一般我们会用到三种方法, 分别是 stopPropagati ...

  3. 转!!Java设置session超时(失效)的时间

    Java设置session超时(失效)的时间   在一般系统登录后,都会设置一个当前session失效的时间,以确保在用户长时间不与服务器交互,自动退出登录,销毁session具体设置的方法有三种:1 ...

  4. 转!!ftp学习

    转自:http://blog.csdn.net/wave_1102/article/details/50651433 FTP (File Transfer Protocol) 可说是最古老的协议之一了 ...

  5. 《COM本质论》COM是一个更好的C++心得分享

    昨天看了<COM本质论>的第一章"COM是一个更好的C++",认为非常有必要做一些笔记,于是整理成这篇文章.我相信你值得拥有. 这篇文章主要讲的内容是:一个实现了高速查 ...

  6. Feature Pyramid Networks for Object Detection

    Feature Pyramid Networks for Object Detection 特征金字塔网络用于目标检测 论文地址:https://arxiv.org/pdf/1612.03144.pd ...

  7. 利用VMware克隆linux虚拟机需要注意的事项

    利用VMware克隆虚拟机需要注意的问题 2018年03月30日 18:20:29 温文尔雅的流氓 阅读数:1343更多 个人分类: linux   版权声明:本文为博主原创文章,未经博主允许不得转载 ...

  8. Ngfor遍历map的方法

    Ngfor可以遍历list和数组,但如果想遍历map,可以使用下面的方式 在TypeScript文件中: let list = Object.keys(MyObject); 在html文件中: *ng ...

  9. 推荐系统第2周--itemCF和userCF

    推荐系统分类 基于应用领域分类:电子商务推荐,社交好友推荐,搜索引擎推荐,信息内容推荐基于设计思想:基于协同过滤的推荐,基于内容的推荐,基于知识的推荐,混合推荐基于使用何种数据:基于用户行为数据的推荐 ...

  10. Python基础学习之 函数

    阅读目录 第一篇:  函数初识 第二篇:  函数命名空间 作用域 闭包 第三篇:  装饰器 第四篇:  装饰器 面试题错误点 第五篇:  迭代器生成器 第六篇:  生成器进阶 第七篇:  递归 第八篇 ...