C++以文件IO方式调用python模块(以调用mediapipe模块中的facemesh为例)

4 篇文章 1 订阅
3 篇文章 0 订阅

C++调用python模块重要方法



前言

最近想在WIndows C++下使用mediapipe,用windows版本配置配了好久没成功,
采用https://stubbornhuang.blog.csdn.net/article/details/119675282?spm=1001.2014.3001.5506
的方法应该是最好的,但是我不会配置。
Python版本跑起来最快,看了Mediapipe的封装调用,成功在VS里使用上了mediapipe,但是打包时又出现了问题,把python环境复制过来时打包不成功。
最后想了两种在C++下调用python的方式:
1.用socket通讯,一个做client端,一个做server端。
2.把python程序封装成可执行文件,在c++里用系统调用。


一、写好python程序

调用meidiapipe模块,输入图片,输出facemesh点位置。

from cv2 import cvtColor
from cv2 import COLOR_BGR2RGB
from cv2 import imread
from mediapipe import solutions
from re import split
from csv import writer
from sys import argv
mp_face_mesh = solutions.face_mesh


def detectImage(image):
    with mp_face_mesh.FaceMesh(
            static_image_mode=True,
            max_num_faces=1,
            min_detection_confidence=0.5) as face_mesh:
        results = face_mesh.process(cvtColor(image, COLOR_BGR2RGB))
        newList2 = []
        for item in results.multi_face_landmarks:
            pattern = r'x: |y: |z: |\n|landmark|{|}'
            result = split(pattern, str(item))  # 以pattern的值 分割字符串
            newList2 = [eval(x) for x in list(result) if len(x) > 2]
            #for idx in range(0, len(newList2), 3):
            #    cv2.circle(image, (int(newList2[idx] * image.shape[1]), int(newList2[idx + 1] * image.shape[0])), 1, (0, 0, 255))
            #cv2.imshow("",image)
            #cv2.waitKey(0)
        return newList2

def main():
    if(len(argv)<2):
        return
    image = imread(str(argv[1])+'.jpg')
    (height, width, channels) = image.shape
    # print(height,width)
    a = detectImage(image)
    # for i in range(0, 468, 1):
    #     # 写入csv文件内容
    #     print([a[i * 3]*width, a[i * 3 + 1]*height])
    #     cv2.circle(image, (int(a[i * 3]*width), int(a[i * 3 + 1]*height)) ,1, (255,0,0), 1)
    # cv2.imshow("image",image)
    # while(True):
    #     if cv2.waitKey(5) & 0xFF == 27:
    #         break
    with open(str(argv[1])+'.csv', 'w+', newline='') as file:
        mywriter = writer(file)
        for i in range(0, 468, 1):
            # 写入csv文件内容
            mywriter.writerow([int(a[i * 3]*width), int(a[i * 3 + 1]*height)])

if __name__ == '__main__':
    main()

二、打包python程序

采用pyinstaller进行打包,
正常py程序打包如下,w表示不弹出命令行,F表示打包成一个文件:
pyinstaller xxx.py -w -F
命令行如下
pyinstaller IO_detectImage.py --add-data=“C:\Users\xujianjun\AppData\Roaming\Python\Python39\site-packages\mediapipe\modules;mediapipe/modules” -w
然后将输出的dist里的IO_detectImage的整个文件包拷贝到vs文件目录下
————————————————————————————————————————————
参考pyinstaller打包Mediapipe遇到的Failed to execute script


三、C++程序里调用

我用的visual studio写的,用_getcwd获取目录地址,再用system函数调用python程序,以下方法C++都可以用

#include "stdafx.h"
#include "IOMediaPipe.h"
#include <fstream>
#include <sstream>
#include <string>
#include <vector>
#include <iostream>
#include <Windows.h>
#include <direct.h>


IOMediaPipe::IOMediaPipe()
{
}


IOMediaPipe::~IOMediaPipe()
{
}

bool IOMediaPipe::savePic(cv::Mat pic)
{
	return cv::imwrite("IO_detect/Temp_Facemesh.jpg", pic);
}



bool IOMediaPipe::predict(std::vector<cv::Point>& res)
{
	/*TCHAR Buffer[100] = TEXT("IO_detect");
	bool flag = SetCurrentDirectory(Buffer);
	if (!flag) return false;*/
	//system("pwd");
	char m_szInitDir[_MAX_PATH];
	std::string pathname = _getcwd(m_szInitDir, _MAX_PATH);
	std::string exename = pathname+ std::string("\\IO_detect\\IO_detect.exe ")+ pathname+ std::string("\\IO_detect\\Temp_Facemesh");
	std::cout << exename << " " << std::endl;
	system(exename.c_str());
	res.clear();
	std::ifstream infile;//定义读取文件流,相对于程序来说是in
	/*TCHAR Buffer[100] = TEXT("..");
	bool flag = SetCurrentDirectory(Buffer);*/
	infile.open("IO_detect/Temp_Facemesh.csv");//打开文件
	std::string line;
	cv::Point p;
	if (infile.eof())
	{
		infile.close();
		std::cout << "error open" << std::endl;
		return false;
	}
	for (int val = 0; val<468; val++) {
		if (std::getline(infile, line)) {
			std::istringstream sin(line);
			std::vector<std::string> fields;
			std::string field;
			while (std::getline(sin, field, ',')) {
				std::cout << field << " ";
				fields.push_back(field);
			}
			p.x = atoi(fields.at(0).data());
			p.y = atoi(fields.at(1).data());
			res.push_back(p);
		}
		else {
			std::cout << "error push in point data!" << std::endl;
			infile.close();
			return false;
		}
	}
	infile.close();
	return true;
}

bool IOMediaPipe::predict(cv::Mat pic, std::vector<cv::Point>& res)
{
	if (!savePic(pic)) return false;
	if (!predict(res)) return false;
	return true;
}

总结

用这个方法能解决C++调用python模块的几乎所有问题,不过执行效率可能有点点慢,后续考虑用RPC通讯模式,能提高执行效率。


感谢阅读,如果对您有帮助,欢迎点赞,关注,收藏

  • 3
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值