Skip to content

Commit

Permalink
优化按键位置检测算法
Browse files Browse the repository at this point in the history
  • Loading branch information
happyme531 committed Jan 22, 2024
1 parent 024f177 commit a52fbad
Show file tree
Hide file tree
Showing 6 changed files with 40 additions and 20 deletions.
5 changes: 3 additions & 2 deletions src/buildconfig.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
//buildconfig.h 由 cmake 从 buildconfig.h.in 自动生成
#pragma once
#define LversionStr L"0.1.3"
#define versionStr "0.1.3"
#define LversionStr L"0.1.4"
#define versionStr "0.1.4"
constexpr int DEFAULT_KEY_THRESHOLD = 6;
constexpr int DEFAULT_LOG_LEVEL = 4;
constexpr int DEFAULT_HOUGH_CIRCLES_THRESHOLD = 60;
3 changes: 2 additions & 1 deletion src/buildconfig.h.in
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,5 @@
#define LversionStr L"${CMAKE_PROJECT_VERSION}"
#define versionStr "${CMAKE_PROJECT_VERSION}"
constexpr int DEFAULT_KEY_THRESHOLD = 6;
constexpr int DEFAULT_LOG_LEVEL = 4;
constexpr int DEFAULT_LOG_LEVEL = 4;
constexpr int DEFAULT_HOUGH_CIRCLES_THRESHOLD = 60;
26 changes: 17 additions & 9 deletions src/keyposfinder.cpp
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
#include "keyposfinder.h"
#include <opencv2/core/mat.hpp>
#include <opencv2/imgproc.hpp>
#include <sstream>
#include <algorithm>
#include <opencv2/opencv.hpp>
#include "utils.h"


void KeyPosFinder::begin(string filePath){
void KeyPosFinder::begin(string filePath, int houghCirclesThreshold_){
houghCirclesThreshold = houghCirclesThreshold_;
ui.addTask(L"检测按键位置");
VideoCapture video(filePath);
if(!video.isOpened()){
Expand All @@ -21,25 +24,30 @@ void KeyPosFinder::begin(string filePath){
ui.logI(strBuf.str());
strBuf.clear();

double scaleFactor = videoHeight/1080.0; //相比1080p的缩放系数
Mat frame;
Mat resizedFrame;
if (logLevel == 5) namedWindow("frames");
bool detectedGUIOpen = false;
//y缩放到480, x等比例
auto targetVideoHeight = 480;
auto targetVideoWidth = videoWidth * targetVideoHeight / videoHeight;
// #pragma omp parallel
while (minFramesCnt != vaildFramesCnt){
//针对某些视频一开始根本没有打开界面的问题,在没有检测到界面时每隔5帧读取一帧,节省时间
if(!video.read(frame)) break;
if(!detectedGUIOpen) video.set(CAP_PROP_POS_FRAMES, video.get(CAP_PROP_POS_FRAMES) + 4); // 跳过4帧

resize(frame,resizedFrame,Size(),0.5,0.5); //宽高缩小一半
resizedFrame = resizedFrame(Rect(Point(0,videoHeight/4),Point(videoWidth/2-1,videoHeight/2-1))); //切去上半部分, 保留下半部分
pyrMeanShiftFiltering(resizedFrame,resizedFrame,15*scaleFactor,100*scaleFactor);

resize(frame,resizedFrame,Size(targetVideoWidth,targetVideoHeight));
resizedFrame = resizedFrame(Rect(Point(0,targetVideoHeight/2),Point(targetVideoWidth-1,targetVideoHeight-1))); //切去上半部分, 保留下半部分
cvtColor(resizedFrame,resizedFrame,COLOR_BGR2GRAY);
//equalizeHist(resizedFrame,resizedFrame);
auto blurredFrame = Mat();
GaussianBlur(resizedFrame, blurredFrame, Size(31,31), 2);
//pyrMeanShiftFiltering(resizedFrame,resizedFrame,15*scaleFactor,100*scaleFactor);
//medianBlur(resizedFrame,resizedFrame,3);
//Canny(resizedFrame,resizedFrame,80,255);
vector<Vec3f> circles;
HoughCircles(resizedFrame,circles, HOUGH_GRADIENT,2,50*scaleFactor,200,55,0,60*scaleFactor);
HoughCircles(blurredFrame,circles, HOUGH_GRADIENT,2,50,200,houghCirclesThreshold,0,60);
ui.updateMsg(L"找到的按键数量:" + to_wstring(circles.size()));
if (!detectedGUIOpen && circles.size() > 10 ){
detectedGUIOpen = true;
Expand All @@ -48,8 +56,8 @@ void KeyPosFinder::begin(string filePath){

if (logLevel == 5) {
for (auto c : circles)
circle(resizedFrame, Point(c[0], c[1]), c[2], Scalar(0, 255, 255), 3);
imshow("frames", resizedFrame);
circle(blurredFrame, Point(c[0], c[1]), c[2], Scalar(0, 255, 255), 3);
imshow("frames", blurredFrame);
waitKey(1); //必须加上,否则预览窗口灰屏卡住
}
//如果有21个圆,保存起来
Expand Down
3 changes: 2 additions & 1 deletion src/keyposfinder.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ class KeyPosFinder {
private:
int vaildFramesCnt = 0;
int minFramesCnt = 20;
int houghCirclesThreshold;
TermUI& ui;
vector<vector<Vec3f>> vaildCircles; //3x7 = 21个按键
array<Vec3f,21> result;
Expand All @@ -22,7 +23,7 @@ class KeyPosFinder {

public:

void begin(string filePath);
void begin(string filePath, int houghCirclesThreshold_ = 60);
array<Vec3f,21>&& getResult(){
return move(result);
}
Expand Down
16 changes: 11 additions & 5 deletions src/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -38,11 +38,16 @@ int main(int argc, char* argv[]) {
parser.add_argument("-o", "--output")
.help("输出文件路径")
.default_value(string("output.mid")); //存储const char*的std::any被any_cast到std::string时会抛异常

parser.add_argument("--key-threshold")
.help("设置按键位置检测的阈值, "
"如果输出的文件中有错音, 可以尝试增加这个值, 如果获取不到按键位置则减少")
.default_value(DEFAULT_HOUGH_CIRCLES_THRESHOLD)
.scan<'i', int>();
//get a parameter which represent the threshold of the note finder
parser.add_argument("-t", "--note-threshold")
.help("设置音符检测的阈值, 如果输出的文件中有大量不存在的音符则增大这个值, 反之减少")
.default_value(DEFAULT_KEY_THRESHOLD);
.default_value(DEFAULT_KEY_THRESHOLD)
.scan<'i', int>();
parser.add_argument("-c", "--notui")
.help("不使用界面")
.default_value(false)
Expand Down Expand Up @@ -97,11 +102,12 @@ ps:我不玩原神)123");
// omp_set_num_threads(omp_get_num_procs());

string filepath = parser.get<string>("input");
KeyPosFinder finder(ui);
finder.begin(filepath);
KeyPosFinder finder(ui);
finder.begin(filepath, parser.get<int>("--key-threshold"));
int startFrame = finder.getStartFrame();
NoteDetector detector(ui);
detector.begin(filepath,finder.getResult(),parser.get<int>("--note-threshold"),startFrame);
detector.begin(filepath, finder.getResult(),
parser.get<int>("--note-threshold"), startFrame);
MidiWriter writer;

//let the output file to be the input file except the extension changed to mid
Expand Down
7 changes: 5 additions & 2 deletions src/notedetector.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -71,8 +71,11 @@ void NoteDetector::begin(string filePath, array<Vec3f, 21> keyPos, int threshold
frameQueue.pop();
frameQueueMutex.unlock();

resize(frame,resizedFrame,Size(),0.5,0.5); //宽高缩小一半,和获取位置时一样
resizedFrame = resizedFrame(Rect(Point(0,videoHeight/4),Point(videoWidth/2-1,videoHeight/2-1))); //切去上半部分, 保留下半部分
// y缩放到480, x等比例 ,和获取位置时一样
auto targetVideoHeight = 480;
auto targetVideoWidth = videoWidth * targetVideoHeight / videoHeight;
resize(frame,resizedFrame,Size(targetVideoWidth,targetVideoHeight));
resizedFrame = resizedFrame(Rect(Point(0,targetVideoHeight/2),Point(targetVideoWidth-1,targetVideoHeight-1))); //切去上半部分, 保留下半部分
cvtColor(resizedFrame,resizedFrame,COLOR_BGR2GRAY); //只关心灰度

//分别获取21个按钮区域的平均颜色
Expand Down

0 comments on commit a52fbad

Please sign in to comment.