| #include <opencv2/dnn.hpp> |
| #include <opencv2/imgproc.hpp> |
| #include <opencv2/highgui.hpp> |
| #include <iostream> |
| #include <string> |
| #include <cmath> |
| #include <vector> |
|
|
| using namespace cv; |
| using namespace cv::dnn; |
| using namespace std; |
|
|
| class Dexined { |
| public: |
| Dexined(const string& modelPath) { |
| loadModel(modelPath); |
| } |
|
|
| |
| void processFrame(const Mat& image, Mat& result) { |
| Mat blob = blobFromImage(image, 1.0, Size(512, 512), Scalar(103.5, 116.2, 123.6), false, false, CV_32F); |
| net.setInput(blob); |
| applyDexined(image, result); |
| } |
|
|
| private: |
| Net net; |
|
|
| |
| void loadModel(const string modelPath) { |
| net = readNetFromONNX(modelPath); |
| net.setPreferableBackend(DNN_BACKEND_DEFAULT); |
| net.setPreferableTarget(DNN_TARGET_CPU); |
| } |
|
|
| |
| static void sigmoid(Mat& input) { |
| exp(-input, input); |
| input = 1.0 / (1.0 + input); |
| } |
|
|
| |
| static pair<Mat, Mat> postProcess(const vector<Mat>& output, int height, int width) { |
| vector<Mat> preds; |
| preds.reserve(output.size()); |
| for (const Mat &p : output) { |
| Mat img; |
| Mat processed; |
| if (p.dims == 4 && p.size[0] == 1 && p.size[1] == 1) { |
| processed = p.reshape(0, {p.size[2], p.size[3]}); |
| } else { |
| processed = p.clone(); |
| } |
| sigmoid(processed); |
| normalize(processed, img, 0, 255, NORM_MINMAX, CV_8U); |
| resize(img, img, Size(width, height)); |
| preds.push_back(img); |
| } |
| Mat fuse = preds.back(); |
| Mat ave = Mat::zeros(height, width, CV_32F); |
| for (Mat &pred : preds) { |
| Mat temp; |
| pred.convertTo(temp, CV_32F); |
| ave += temp; |
| } |
| ave /= static_cast<float>(preds.size()); |
| ave.convertTo(ave, CV_8U); |
| return {fuse, ave}; |
| } |
|
|
| |
| void applyDexined(const Mat& image, Mat& result) { |
| int originalWidth = image.cols; |
| int originalHeight = image.rows; |
| vector<Mat> outputs; |
| net.forward(outputs); |
| pair<Mat, Mat> res = postProcess(outputs, originalHeight, originalWidth); |
| result = res.first; |
| } |
| }; |
|
|
| int main(int argc, char** argv) { |
| const string about = |
| "This sample demonstrates edge detection with dexined edge detection techniques.\n\n"; |
| const string keys = |
| "{ help h | | Print help message. }" |
| "{ input i | | Path to input image or video file. Skip this argument to capture frames from a camera.}" |
| "{ model | edge_detection_dexined_2024sep.onnx | Path to the dexined.onnx model file }"; |
|
|
| CommandLineParser parser(argc, argv, keys); |
| if (parser.has("help")) |
| { |
| cout << about << endl; |
| parser.printMessage(); |
| return -1; |
| } |
|
|
| parser = CommandLineParser(argc, argv, keys); |
| string model = parser.get<String>("model"); |
| parser.about(about); |
|
|
| VideoCapture cap; |
| if (parser.has("input")) |
| cap.open(samples::findFile(parser.get<String>("input"))); |
| else |
| cap.open(0); |
|
|
| namedWindow("Input", WINDOW_AUTOSIZE); |
| namedWindow("Output", WINDOW_AUTOSIZE); |
| moveWindow("Output", 200, 0); |
|
|
| |
| Dexined dexined(model); |
| Mat image; |
|
|
| for (;;){ |
| cap >> image; |
| if (image.empty()) |
| { |
| cout << "Press any key to exit" << endl; |
| waitKey(); |
| break; |
| } |
|
|
| Mat result; |
| dexined.processFrame(image, result); |
|
|
| imshow("Input", image); |
| imshow("Output", result); |
| int key = waitKey(1); |
| if (key == 27 || key == 'q') |
| { |
| break; |
| } |
| } |
| destroyAllWindows(); |
| return 0; |
| } |
|
|