세그멘테이션 레이블링시 정보를 저장하기 위해 압축 방법들을 비교해 보았다.
우선적으로 이진 마스크에 대한 압축률을 비교해 보았다.
(아래 포스트는 jupyter로 작성됨)
#include<iostream>
#include<string>
#include<opencv2/opencv.hpp>
#include<zlib.h>
struct LabelSegmentation {
int width = 0;
int height = 0;
std::vector<uchar> data;
public:
int Compression(const cv::Mat& in) {
height = in.rows;
width = in.cols;
data.assign(height*width, 0);
Bytef* inbyte = static_cast<Bytef*>(in.data);
size_t insize = in.rows* in.cols;
z_stream defstream = { 0 };
defstream.avail_in = insize + 1;
defstream.next_in = inbyte;
defstream.avail_out = width*height;
defstream.next_out = static_cast<Bytef*>(data.data());
deflateInit(&defstream, Z_BEST_COMPRESSION);
deflate(&defstream, Z_FINISH);
deflateEnd(&defstream);
data.resize(defstream.total_out);
return defstream.total_out;
}
cv::Mat Decompression() {
cv::Mat out = cv::Mat::zeros(height, width, CV_8UC1);
z_stream infstream = { 0 };
infstream.avail_in = data.size();
infstream.next_in = static_cast<Bytef*>(data.data());
infstream.avail_out = height*width;
infstream.next_out = static_cast<Bytef*>(out.data);
inflateInit(&infstream);
inflate(&infstream, Z_NO_FLUSH);
inflateEnd(&infstream);
return out;
}
};
std::vector<int> RLE(const cv::Mat& mask) {
std::vector<int> rle;
rle.push_back(mask.rows);
rle.push_back(mask.cols);
auto it = mask.begin<uchar>();
int e = 1;
int b = *it > 0 ? 1 : -1;
it++;
while (it != mask.end<uchar>()) {
int p = *it > 0 ? 1 : -1;
if (p == b)e++;
else {
rle.push_back(e*b);
b = p;
e = 1;
}
it++;;
}
rle.push_back(e*b);
return rle;
}
void image_show(cv::Mat img,std::string name,int width=384){
cv::Mat img2;
cv::resize(img,img2,cv::Size(width,img.rows*width/img.cols));
cv::imshow(name,img2);
}
#define MeasureTime(RET,EXPRESSION,NAME) do{\
auto t = cv::getTickCount();\
RET = EXPRESSION;\
std::cout << NAME << ": " << (cv::getTickCount() - t) / cv::getTickFrequency() << std::endl;\
}while(0)
std::vector<std::string> urls={
"https://i.stack.imgur.com/5vb9J.png",
"https://i.stack.imgur.com/Ga5Pe.png",
"https://i.stack.imgur.com/nm2HM.png",
"https://cs-people.bu.edu/sidmys/cs585/A2/binary_mask/skintone_mask.png"};
for(auto& url:urls){
std::cout << url << std::endl;
cv::Mat img=cv::imread(url.c_str());
cv::cvtColor(img, img, cv::COLOR_BGR2GRAY);
cv::threshold(img, img, 1, 255, cv::THRESH_BINARY);
std::cout << "width: " << img.cols << "\t" << "height: " << img.rows << std::endl;
image_show(img,"image");
LabelSegmentation lbl;
MeasureTime(int dummy,lbl.Compression(img),"Time(Deflate)");
std::vector<int> rle;
MeasureTime(rle,RLE(img),"Time(RLE)");
std::vector<uchar> pngbuf;
MeasureTime(bool dummy,cv::imencode(".png",img, pngbuf),"Time(PNG)");
std::cout << "RLE: " << rle.size() * 4 << std::endl;
std::cout << "Deflate: " << lbl.data.size() + 8 << std::endl;
std::cout << "PNG: " << pngbuf.size() << std::endl;
for(int t=0;t<100;t++)std::cout<< "-";std::cout << std::endl;
}
https://i.stack.imgur.com/5vb9J.png
width: 1024 height: 768
image
Time(Deflate): 0.0119147
Time(RLE): 0.575732
Time(PNG): 0.00367758
RLE: 3644
Deflate: 1944
PNG: 4141
https://i.stack.imgur.com/Ga5Pe.png
width: 512 height: 512
image
Time(Deflate): 0.0143451
Time(RLE): 0.202859
Time(PNG): 0.0016504
RLE: 3948
Deflate: 1460
PNG: 3046
https://i.stack.imgur.com/nm2HM.png
width: 488 height: 275
image
Time(Deflate): 0.0263108
Time(RLE): 0.0985578
Time(PNG): 0.000986006
RLE: 8588
Deflate: 2227
PNG: 3950
https://cs-people.bu.edu/sidmys/cs585/A2/binary_mask/skintone_mask.png
width: 990 height: 557
image
Time(Deflate): 0.0784132
Time(RLE): 0.437506
Time(PNG): 0.00400376
RLE: 28924
Deflate: 8070
PNG: 11730