QQ 282397369
需求
老革命碰到新问题,用户发现在试玩的时候,有一个平台需要按住虚框进行操作,目前的脚本还没有这个功能,需要实现一下下。
不怕客户没爱好,就怕客户没需求。

实现
首先是颜色过滤,然后找连通域,再拼成矩形框数据。当然,矩形框数据只需找上下左右4个坐标分量,这个可以通过投影找最大两个数值来确定。
核心实现,肯定还得C来
考虑实用性,把二值化这个步骤用字符串来参数化,这样就可以实现彩色、灰度、通道方式过滤。
先设计一个函数:
TRect __fastcall CvHelper::GetRect_Dash(cv::Mat& srcMat, UnicodeString binaryMethod) {
TRect result(-1, -1, -1, -1);
UnicodeString type = THelper::String::GetStringAt(binaryMethod, L",", 0).Trim();
UnicodeString value1 = THelper::String::GetStringAt(binaryMethod, L",", 1).Trim();
UnicodeString value2 = THelper::String::GetStringAt(binaryMethod, L",", 2).Trim();
cv::Mat binaryMat;
int v1 = ::TTypeConvert::Str2Int(value1);
if(THelper::String::IsSame(L"Color", type, !DRGRAPH_FLAG_SENSITIVE)) {
if(value2.Length()) {
int delta = ::TTypeConvert::Str2Int(value2);
binaryMat = CvHelper::BuildTransMaskMat(srcMat, TColor(v1), delta);
} else
binaryMat = CvHelper::BuildTransMaskMat_ColorPass(srcMat, v1);
} else if(THelper::String::IsSame(L"Gray", type, !DRGRAPH_FLAG_SENSITIVE)) {
if(value2.Length()) {
int delta = ::TTypeConvert::Str2Int(value2);
binaryMat = CvHelper::BuildTransMaskMat(srcMat, BYTE(v1), delta);
} else
binaryMat = CvHelper::BuildTransMaskMat_GRAY(srcMat, BYTE(v1));
} else if(THelper::String::IsSame(L"Channel", type, !DRGRAPH_FLAG_SENSITIVE)) {
NChannelType channel = THelper::String::IsSame(L"RED", value1, !DRGRAPH_FLAG_SENSITIVE) ? nctRed :
THelper::String::IsSame(L"BLUE", value1, !DRGRAPH_FLAG_SENSITIVE) ? nctBlue : nctGreen;
int delta = ::TTypeConvert::Str2Int(value2);
binaryMat = CvHelper::BuildTransMaskMat_Channel(srcMat, channel, delta);
}
if(binaryMat.empty())
return result;
CvHelper::Debug::LogMat(srcMat, L"虚线框识别 - 原图");
CvHelper::Debug::LogMat(binaryMat, L"虚线框识别 - 二值图");
CvRects rects = CvHelper::GetAllDomain(binaryMat, nssX, L"", CV_RETR_LIST);
CvHelper::Debug::LogMatWithRects(srcMat, rects);
int * rowValue = new int[srcMat.rows];
int * colValue = new int[srcMat.cols];
ZeroMemory(rowValue, srcMat.rows * sizeof(int));
ZeroMemory(colValue, srcMat.cols * sizeof(int));
for(int i = rects.size() - 1; i >= 0; --i) {
CvRect r = rects[i];
if(r.height > maxLength || r.width > maxLength)
rects.erase(rects.begin() + i);
else {
int x = r.x + r.width / 2;
int y = r.y + r.height / 2;
rowValue[y] += 1;
colValue[x] += 1;
}
}
int left = localGetMaxIndex(colValue, srcMat.cols);
int right = -1;
if(left >= 0) {
colValue[left] = 0;
right = localGetMaxIndex(colValue, srcMat.cols);
}
int top = GetMaxIndex(rowValue, srcMat.rows);
int bottom = -1;
if(top >= 0) {
rowValue[top] = 0;
bottom = GetMaxIndex(rowValue, srcMat.rows);
}
delete rowValue;
delete colValue;
if(left < 0 || right < 0 || top < 0 || bottom < 0)
return result;
result.left = std::min(left, right);
result.top = std::min(top, bottom);
result.right = std::max(left, right);
result.bottom = std::max(top, bottom);
CvHelper::Debug::LogMatWithRects(srcMat, rects);
return result;
}
经测试,可以正确识别出虚线框

LUA调用
增加一个API函数GetRect_Dash供LUA调用,返回矩形区域即可。
local t, x, y, w, h = cv:GetRect_Dash(realTimeMat, "Channel, BLUE, 80")
if(x > 0) then
Click(string.format("%d, %d", x + w / 2, y + h / 2))
end
结果:

如此甚好。
1506

被折叠的 条评论
为什么被折叠?



