-、屏幕截图:
长截图时,整个截图界面其实是个异形窗体, 其大体思路是先创建一个半透明的窗体,然后根据截图区域来创建异形窗体。
异形窗体:
hRgn :=CreateRectRgn(rt.left,rt.top,rt.right,rt.bottom); //rt为截图区域
hWndRect:= CreateRgn(0,0,self.width,self.height);
if CombineRgn(hWndRect,hWndRect,hRgn,Rgn_Xor)<>Error then
SetWindowRgn(Handle,hWndRect,False);
二、Hook windows消息
(1)Hook WH_MOUSE_LL
其目的是控制滚动速度,方便截图。同时要将截图区域的滚动条禁用,以免影响连续截图。
WH_MOUSE_LLProc(icode:integer;w:Wparam;l:Lparam):LRESULT;stdcall
begin
if (icode<0) or (icode<> hc_action) then
begin
Result:= callNextHookEx(g_mouseWheel_hook,icode,w,l);
exit;
end;
if(w<> WM_MOUSELWHEEL) and( w<>WM_LBUTTONDOWN) and (w<>WM_LBUTTONUP) then
begin
Result:=callNextHookEx(g_mouseWheel_hook,icode,w,l);
exit(-1); //返回 <0的值 才能阻止消息进入windows 消息循环。
end
mslhook = PMSLLHOOKSTRUCT(l);
if not assign(mslhook ) then
begin
Result:=callNextHookEx(g_mouseWheel_hook,icode,w,l);
exit;
end
if( w<>WM_LBUTTOnDOWN) or(W<>WM_LBUttonUp) then exit(-1);
iwheeldelta = short(HiWord(mslhook^.mouseData)); //根据iWheeldelta的值 便可知道 是向上滚动还是向下滚动.
//控制滚动速度,根据需要,可自行调整
if i>=3 then
begin
iTickcount :=GetTickCount;
if iTickount - FtickCount>300 then
begin
//发送消息到主窗体,实现拼图功能
PostMessage(Form.Handle, WM_User+100,iWheelDelta,0);
FTickCount := iTickCount;
i:=0;
end
else
Exit(-1);
end
else
begin
inc(i);
exit(-1);
end
result :=CallnextHookEx(g_MouseWheel_Hook,icode,w,l);
end;
*(2) 如果想做类似QQ的那种点击截图区域后,可自行滚动截图的功能,还需要Hook , WM_GetMessage.
在此消息的HookProc 里面自行处理 WM_MouseWheel消息。
三、拼图
此部份是最重要的一部份,最简单的做法 是利用 opencv的surf、orb 等算法实现图片拼接。
参考网址:https://www.cnblogs.com/skyfsm/p/7411961.html
上述网址只是给出了两张图片的拼接,而且是左右拼接,而我们截图需要的上下拼接,最简单直接的做法就是先将图片旋转90度,拼接完成后再旋转回来
为了提高效率与准确率,最好使用 “增量拼接'的方式,也就是
A 与B拼接后 生成Ab,
当与C拼接时,不要用AB与C拼接,而要使用 b与C拼接生成BC,然后将AB中的B扣掉 合并生成ABC.
上面的无论surf算法、还是orb算法,都存一个问题。如果 两张图片 有 2个以上的重叠区域时,最后合并生成的图片ABC会有问题。最简单的实验就是去截图带导航栏的门户网站,一试便知。
仔细分析,我们会发现 具有重叠区域的A、B两张图的拼接,转成数学问题,其本质就是求两个集合的最大交集。
所以 自写算法如下:
f b c d g --- list2
a 0 0 0 0 0
b 0 1 0 0 0
c 0 0 2 0 0
d 0 0 0 3 0
e 0 0 0 0 0
f 0 0 0 0 0
|
list1
void max_substring(const std::vector<float> &a1,const std::vector<float> &a2,
int & max1_index, int & max2_index, int & max_count)
{
int len1 = a1.size(); int len2 = a2.size();
std::vector< std::vector<int16_t> > mat(len1, std::vector<int16_t>(len2));
max_count = 0; max1_index = 0; max2_index = 0;
for(int i=0;i<len1;i++)
for(int j=0;j<len2;j++)
{
if(i==0 || j==0) { mat[i][j] = 0; continue; }
if(fabs(a1[i]-a2[j])<0.5)
{
int count = mat[i][j] = mat[i-1][j-1] + 1;
if(count>max_count) { max_count=count; max1_index=i-count+1; max2_index=j-count+1; }
}
else { mat[i][j] = 0; }
}
}
注明:上述算法也有些缺陷,并不满足所有的条件,当图片是 纯 白底、黑字的图片时,也会出现拼图错误,我想这也是QQ长截图有时候也不灵的原因吧。