提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
“第一次写博客,记录一下吧”
当时写这个脚本是为了方便评估模型(当时用的是tensorrt,c++),直接将solov2推理的结果保存成了labelme格式的Json文件{(所以这次的代码也是c++代码哈)也是为了方便标数据,labelme打开可以直接微调坐标成标签},后来想通过json文件评估模型,就把coco的大json文件转换成labelme格式的json文件,方便以后用c++推理然后评估。所以废话不多说直接上代码
使用labelme需要的图片编码
#pragma once
#include
//#include "opencv2/opencv.hpp"
using namespace std;
class ZBase64
{
public:
/*编码
DataByte
[in]输入的数据长度,以字节为单位
*/
string Encode(const unsigned char* Data, int DataByte);
/*解码
DataByte
[in]输入的数据长度,以字节为单位
OutByte
[out]输出的数据长度,以字节为单位,请不要通过返回值计算
输出数据的长度
*/
string Decode(const char* Data, int DataByte, int& OutByte);
//string img_to_base64(std::string img_path);
};
#include "ZBase64.h"
string ZBase64::Encode(const unsigned char* Data, int DataByte)
{
//编码表
const char EncodeTable[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
//返回值
string strEncode;
unsigned char Tmp[4] = { 0 };
int LineLength = 0;
for (int i = 0; i < (int)(DataByte / 3); i++)
{
Tmp[1] = *Data++;
Tmp[2] = *Data++;
Tmp[3] = *Data++;
strEncode += EncodeTable[Tmp[1] >> 2];
strEncode += EncodeTable[((Tmp[1] << 4) | (Tmp[2] >> 4)) & 0x3F];
strEncode += EncodeTable[((Tmp[2] << 2) | (Tmp[3] >> 6)) & 0x3F];
strEncode += EncodeTable[Tmp[3] & 0x3F];
if (LineLength += 4, LineLength == 76) { strEncode += "\r\n"; LineLength = 0; }
}
//对剩余数据进行编码
int Mod = DataByte % 3;
if (Mod == 1)
{
Tmp[1] = *Data++;
strEncode += EncodeTable[(Tmp[1] & 0xFC) >> 2];
strEncode += EncodeTable[((Tmp[1] & 0x03) << 4)];
strEncode += "==";
}
else if (Mod == 2)
{
Tmp[1] = *Data++;
Tmp[2] = *Data++;
strEncode += EncodeTable[(Tmp[1] & 0xFC) >> 2];
strEncode += EncodeTable[((Tmp[1] & 0x03) << 4) | ((Tmp[2] & 0xF0) >> 4)];
strEncode += EncodeTable[((Tmp[2] & 0x0F) << 2)];
strEncode += "=";
}
return strEncode;
}
string ZBase64::Decode(const char* Data, int DataByte, int& OutByte)
{
//解码表
const char DecodeTable[] =
{
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
62, // '+'
0, 0, 0,
63, // '/'
52, 53, 54, 55, 56, 57, 58, 59, 60, 61, // '0'-'9'
0, 0, 0, 0, 0, 0, 0,
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12,
13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, // 'A'-'Z'
0, 0, 0, 0, 0, 0,
26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38,
39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, // 'a'-'z'
};
//返回值
string strDecode;
int nValue;
int i = 0;
while (i < DataByte)
{
if (*Data != '\r' && *Data != '\n')
{
nValue = DecodeTable[*Data++] << 18;
nValue += DecodeTable[*Data++] << 12;
strDecode += (nValue & 0x00FF0000) >> 16;
OutByte++;
if (*Data != '=')
{
nValue += DecodeTable[*Data++] << 6;
strDecode += (nValue & 0x0000FF00) >> 8;
OutByte++;
if (*Data != '=')
{
nValue += DecodeTable[*Data++];
strDecode += nValue & 0x000000FF;
OutByte++;
}
}
i += 4;
}
else// 回车换行,跳过
{
Data++;
i++;
}
}
return strDecode;
}
注意!!!
0 1
1 2
2 3
3 4
4 5
5 6
6 7
7 8
8 9
9 10
10 11
11 13
12 14
13 15
14 16
15 17
16 18
17 19
18 20
19 21
20 22
21 23
22 24
23 25
24 27
25 28
26 31
27 32
28 33
29 34
30 35
31 36
32 37
33 38
34 39
35 40
36 41
37 42
38 43
39 44
40 46
41 47
42 48
43 49
44 50
45 51
46 52
47 53
48 54
49 55
50 56
51 57
52 58
53 59
54 60
55 61
56 62
57 63
58 64
59 65
60 67
61 70
62 72
63 73
64 74
65 75
66 76
67 77
68 78
69 79
70 80
71 81
72 82
73 84
74 85
75 86
76 87
77 88
78 89
79 90
注意!!!
CocoJson2LabelmeJson()中需要更改的路径有
json_val2017 // 要保存的json文件目录
img_val2017 // coco图片目录
txt_path // coco标签对应字典
main()中需要更改的路径有
image_path //coco图片路径
json_path //coco大json文件路径
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include "Zbase64.h"
#include
#include
#include
//#include "torch/torch.h"
//#include
#include "ZBase64.h"
using namespace std;
int read_files_in_dir(const char *p_dir_name, std::vector<std::string> &file_names)
{
DIR *p_dir = opendir(p_dir_name);
if (p_dir == nullptr) {
return -1;
}
struct dirent* p_file = nullptr;
while ((p_file = readdir(p_dir)) != nullptr) {
if (strcmp(p_file->d_name, ".") != 0 &&
strcmp(p_file->d_name, "..") != 0) {
std::string cur_file_name(p_file->d_name);
file_names.push_back(cur_file_name);
}
}
closedir(p_dir);
return 0;
}
void CocoJson2LabelmeJson(const std::string & file, int & w, int & h, std::vector<std::string> file_names)
{
std::string txt_path = "D:/vspy_obj/evaluation/evaluate/coco_class.txt"; // coco的id转换txt文件
std::ifstream infile;
infile.open(txt_path, ios::in);
std::map<std::string, std::string> key_info;
if (infile.is_open())
{
std::string line;
while (getline(infile, line))
{
key_info.insert(pair<std::string, std::string>(line.substr(line.rfind(" ") + 1, line.size()), line.substr(0, line.find_first_of(" "))));
}
infile.close();
}
else
{
std::cerr << "Error loading the class names!\n";
}
Json::CharReaderBuilder reader;
Json::Value root, annotations, points;
std::ifstream ifs;
std::cout << "loading " << file << " file ..." << std::endl;
ifs.open(file, ios::binary);
if (!ifs.is_open())
{
std::cout << "Error opening json file\n";
return;
}
std::string json_val2017 = "D:/dataset/coco2017/val2017_json/"; // 要保存的文件目录
std::string img_val2017 = "D:/dataset/coco2017/val2017/"; // coco图片目录
JSONCPP_STRING errs;
bool res = Json::parseFromStream(reader, ifs, &root, &errs);
if (!res || !errs.empty())
{
std::cout << "parseJson error! " << errs << std::endl;
return;
}
auto names = root.getMemberNames();
annotations = root["annotations"];
for (int j = 0; j < names.size(); j++)
{
std::cout << names[j] << std::endl;
}
for (size_t i = 0; i < file_names.size(); i++)
{
std::cout << "处理第 "<< i << " 张图片" << std::endl;
int index = 0;
int num_obj = 0;
for (int j = 0; j < annotations.size(); j++)
{
int length = annotations[j]["image_id"].asString().size();
std::string zero = "0";
std::string zeros = "";
for (int k = 0; k < 12 - length; k++)
{
zeros += zero;
}
if (file_names[i] == zeros + annotations[j]["image_id"].asString() + ".jpg")
{
bool iscrowd = false;
std::string json_path = json_val2017 + zeros + annotations[j]["image_id"].asString() + ".json";
std::string image_path = img_val2017 + file_names[i];
cv::Mat img = cv::imread(image_path);
///<
if (index == 0)
if (!write_base642json(img, json_path))
std::cout << "convert jpg2base64 successfull !" << std::endl;
///<
Json::CharReaderBuilder s_reader;
Json::Value s_root, s_shape, s_shape_rect, points;
std::ifstream s_ifs;
s_ifs.open(json_path, ios::binary);
if (!s_ifs.is_open())
{
std::cout << "Error opening json file\n";
return;
}
JSONCPP_STRING s_errs;
bool res = Json::parseFromStream(s_reader, s_ifs, &s_root, &s_errs);
if (!res || !s_errs.empty())
{
std::cout << "parseJson error! " << s_errs << std::endl;
return;
}
Json::StreamWriterBuilder writerBuilder;
if (index == 0)
{
s_root["imageHeight"] = Json::Value(img.rows);
s_root["imageWidth"] = Json::Value(img.cols);
s_root["imagePath"] = Json::Value(image_path);
}
if (annotations[j]["iscrowd"] == 0)
{
int s_index = 0;
int anno_num = annotations[j]["segmentation"][0].size();
for (int m = 0; m < anno_num; m++)
{
Json::Value point;
point[m % 2] = annotations[j]["segmentation"][0][m];
point[m % 2 + 1] = annotations[j]["segmentation"][0][m + 1];
points[s_index] = point;
m++;
s_index++;
}
s_shape["label"] = key_info[annotations[j]["category_id"].asString()];
s_shape["points"] = points;
s_shape["group_id"] = Json::nullValue;
s_shape["shape_type"] = "polygon";
}
else if (annotations[j]["iscrowd"] == 1)
{
iscrowd = true;
int mask_w = annotations[j]["segmentation"]["size"][1].asInt();
int mask_h = annotations[j]["segmentation"]["size"][0].asInt();
cv::Mat mask = cv::Mat::zeros(cv::Size(mask_w, mask_h), CV_8UC1);
int sum_count = 0;
int anno_num = annotations[j]["segmentation"]["counts"].size();
for (int m = 0; m < anno_num - 1; m++)
{
int point_x;
int point_y;
sum_count += annotations[j]["segmentation"]["counts"][m].asInt();
point_x = sum_count / mask_h;
point_y = sum_count % mask_h;
sum_count += annotations[j]["segmentation"]["counts"][m + 1].asInt();
int index_mask = annotations[j]["segmentation"]["counts"][m + 1].asInt();
for (int n = 0; n < index_mask; n++)
{
int ratio = (point_y + n) / mask_h;
int yu = (point_y + n) % mask_h;
if (point_y + n >= mask_h)
{
mask.at<uchar>(yu, point_y + ratio) = 255; //
}
else
{
mask.at<uchar>(point_y + n, point_x) = 255;
}
if (n % 256 == 0)
{
//cv::imshow("mask", mask);
//cv::waitKey(1);
}
}
m++;
}
std::vector<std::vector<cv::Point>> contours;
cv::findContours(mask, contours, cv::RETR_EXTERNAL, cv::CHAIN_APPROX_SIMPLE);
//cv::imshow("mask", mask);
//cv::waitKey();
if (contours.size())
{
for (int k = 0; k < contours.size(); k++)
{
Json::Value points_s;
int s_index = 0;
if (contours[k].size() > 10)
{
for (size_t l = 0; l < contours[k].size(); l++)
{
Json::Value point;
point[0] = contours[k][l].x;
point[1] = contours[k][l].y;
points_s[s_index] = point;
s_index++;
}
s_shape["group_id"] = 0;
s_shape["points"] = points_s;
s_shape["shape_type"] = "polygon";
s_shape["label"] = key_info[annotations[j]["category_id"].asString()];
s_root["shapes"][num_obj] = s_shape;
num_obj++;
}
}
}
}
s_shape_rect["label"] = key_info[annotations[j]["category_id"].asString()];
s_shape_rect["points"][0][0] = annotations[j]["bbox"][0];
s_shape_rect["points"][0][1] = annotations[j]["bbox"][1];
s_shape_rect["points"][1][0] = Json::Value(annotations[j]["bbox"][0].asFloat() + annotations[j]["bbox"][2].asFloat());
s_shape_rect["points"][1][1] = Json::Value(annotations[j]["bbox"][1].asFloat() + annotations[j]["bbox"][3].asFloat());
s_shape_rect["shape_type"] = "rectangle";
if (!iscrowd)
{
s_root["shapes"][num_obj] = s_shape;
s_root["shapes"][num_obj + 1] = s_shape_rect;
}
else
{
s_root["shapes"][num_obj] = s_shape_rect;
}
std::ofstream os;
os.open(json_path, std::ios::out);
if (!os.is_open())
{
std::cout << "Error opening json file\n";
return;
}
std::unique_ptr<Json::StreamWriter> jsonWriter(writerBuilder.newStreamWriter());
jsonWriter->write(s_root, &os);
os.close();
//if (index == 0)
// std::cout << "" << i << " --> " << file_names[i] << std::endl;
//std::cout << annotations[j]["category_id"] << " ";
index++;
if (!iscrowd)
{
num_obj += 2;
}
else
{
num_obj += 1;
}
}
}
}
}
int main()
{
///< 实例分割 coco大json文件转为以图片为单位的小单位文件
int image_w;
int image_h;
std::string image_path = "D:/dataset/coco2017/val2017/";
std::string json_path = "D:/dataset/coco2017/annotations/instances_val2017.json";
std::vector<std::string> file_names;
//cv::glob(image_path, file_names);
if (read_files_in_dir(image_path.c_str(), file_names) < 0)
{
std::cerr << "read failed" << std::endl;
return -1;
}
CocoJson2LabelmeJson(json_path, image_w, image_h, file_names);
std::cout << "转换完成" << std::endl;
return 0;
}
配置release跑的会快一些,处理掩码部分可能有一些误差(可修改缩小),代码写的不简洁请谅解,有问题的话可以在下面评论,我会相应修改。