CNN卷积网络图像前处理
说明
- PreprocessBase: 抽象基类,子类需要实现operator(),实现图像前处理运算
- CHWFP32Preprocess: 一个实现用例
- test_preprocess.cpp : 测试代码(来源ResNet50)
源码
PreprocessBase
- Preprocess.h
#pragma once
#include <opencv2/opencv.hpp>
#include <string>
#include <stdint.h>
class PreprocessBase{
public:
static inline void resize(cv::Mat &img, int size);
static inline void center_crop(cv::Mat &img, int crop_size, cv::Mat &oimg);
static inline float half_to_float(const uint16_t x);
static inline uint16_t float_to_half(const float x);
public:
virtual void operator()(const std::string &imgfile, void *img_out)=0;
virtual ~PreprocessBase()=0;
};
inline uint32_t
as_uint(const float x)
{
return *(uint32_t*)&x;
}
inline float
as_float(const uint32_t x) {
return *(float*)&x;
}
inline float
PreprocessBase::half_to_float(const uint16_t x)
{
const uint e = (x&0x7C00)>>10;
const uint m = (x&0x03FF)<<13;
const uint v = as_uint((float)m)>>23;
return as_float((x&0x8000)<<16 | (e!=0)*((e+112)<<23|m) | ((e==0)&(m!=0))*((v-37)<<23|((m<<(150-v))&0x007FE000)));
}
inline uint16_t
PreprocessBase::float_to_half(const float x)
{
const uint b = as_uint(x)+0x00001000;
const uint e = (b&0x7F800000)>>23;
const uint m = b&0x007FFFFF;
return (b&0x80000000)>>16 | (e>112)*((((e-112)<<10)&0x7C00)|m>>13) | ((e<113)&(e>101))*((((0x007FF000+m)>>(125-e))+1)>>1) | (e>143)*0x7FFF;
}
typedef struct HalfFloat{
uint16_t x;
inline explicit operator float()
{
return PreprocessBase::half_to_float(x);
}
} float16;
inline void
PreprocessBase::resize(cv::Mat &img, int size)
{
auto w=img.cols;
auto h=img.rows;
int ow,oh;
if(w<h)
{
ow=size;
oh=int(size*(double)h/w);
}
else
{
oh=size;
ow=int(size*(double)w/h);
}
cv::resize(img, img, cv::Size(ow,oh));
}
inline void
PreprocessBase::center_crop(cv::Mat &img, int crop_size, cv::Mat &oimg)
{
CV_Assert(crop_size<=img.cols);
CV_Assert(crop_size<=img.rows);
auto roi = img(cv::Rect((img.cols - crop_size) / 2, (img.rows - crop_size) / 2, crop_size, crop_size));
roi.copyTo(oimg, cv::Mat(roi.rows, roi.cols, roi.depth(), cv::Scalar(1)));
return;
}
- Preprocess.cpp
#include "PreprocessBase.h"
PreprocessBase::~PreprocessBase(){}
- CHWFP32Preprocess.h
#include "PreprocessBase.h"
#include<vector>
#include<omp.h>
class CHWFP32Preprocess: public PreprocessBase
{
public:
using ResultType=float;
using ImageType=uint8_t;
private:
int m_crop_size;
int m_size;
float m_scale;
float m_mean_bgr[3];
private:
void resize();
void center_crop();
template<int channel>
void apply_scale_and_mean(float *out) const;
private:
cv::Mat m_resized_img;
cv::Mat m_cropped_img;
std::vector<cv::Mat> m_bgr;
public:
CHWFP32Preprocess(int crop_size=224, float scale=1/128.0f, float mean_b=128.0f, float mean_g=128.0f, float mean_r=128.0f):
m_crop_size(crop_size),m_scale(scale),m_mean_bgr{mean_b,mean_g,mean_r}
{
CV_Assert(crop_size>100 && crop_size<256);
CV_Assert(scale>0 && scale<=1);
CV_Assert(mean_b>0 && mean_b<256);
CV_Assert(mean_g>0 && mean_g<256);
CV_Assert(mean_r>0 && mean_r<256);
m_size=m_crop_size*m_crop_size;
}
public:
void operator()(const std::string &imgfile,void *img_out) override;
};
template<int channel>
void CHWFP32Preprocess::apply_scale_and_mean(ResultType *out) const
{
static_assert(channel>=0 && channel<=2);
float mean=m_mean_bgr[channel];
uint8_t *data=m_bgr[channel].data;
for(int i=0; i<m_size; i++)
{
out[i]=ResultType((data[i]-mean)*m_scale);
}
return;
}
- CHWFP32Preprocess.cpp
#include "CHWFP32Preprocess.h"
void CHWFP32Preprocess::operator()(const std::string &imgfile, void *img_out)
{
CV_Assert(img_out!=nullptr);
m_resized_img=cv::imread(imgfile);
CV_Assert(m_resized_img.data!=nullptr);
PreprocessBase::resize(m_resized_img, 256);
PreprocessBase::center_crop(m_resized_img, m_crop_size, m_cropped_img);
cv::split(m_cropped_img,m_bgr);
ResultType *out=static_cast<ResultType*>(img_out);
#pragma omp parallel sections num_threads(3)
{
apply_scale_and_mean<0>(out+0*m_size);
#pragma omp section
apply_scale_and_mean<1>(out+1*m_size);
#pragma omp section
apply_scale_and_mean<2>(out+2*m_size);
}
}
- test_preprocess.cpp
#include "CHWFP32Preprocess.h"
#include <memory>
void test()
{
std::string imgfile{"1.jpg"};
int crop_size=224;
size_t size=crop_size*crop_size;
std::unique_ptr<PreprocessBase> preprocessor{new CHWFP32Preprocess{crop_size,1.0f,103.939f,116.779f,123.68f}};
using ResultType=CHWFP32Preprocess::ResultType;
auto *oimg=new ResultType[3*crop_size*crop_size];
(*preprocessor)(imgfile,oimg);
for(size_t i=0; i<crop_size;i+=50)
for(size_t j=0; j<crop_size;j+=50)
{
size_t k=i*crop_size+j;
float b=float(oimg[k]);
float g=float(oimg[k+size]);
float r=float(oimg[k+2*size]);
printf("img[%d,%d]=(%g,%g,%g)\n",(int)i,(int)j,b,g,r);
}
size_t k=size-1;
float b=float(oimg[k]);
float g=float(oimg[k+size]);
float r=float(oimg[k+2*size]);
printf("img[%d,%d]=(%g,%g,%g)\n",(int)crop_size-1,(int)crop_size-1, b,g,r);
delete []oimg;
}
int
main(int argc, char **argv)
{
test();
return(0);
}
|