parent
2b8ed124f2
commit
be395e5981
5 changed files with 509 additions and 56 deletions
@ -0,0 +1,343 @@ |
||||
#include "precomp.hpp" |
||||
#include "opencv2/imgproc.hpp" |
||||
#include "opencv2/core.hpp" |
||||
|
||||
|
||||
|
||||
#include <iostream> |
||||
#include <fstream> |
||||
#include <sstream> |
||||
#include <queue> |
||||
#include <algorithm> |
||||
#include <iosfwd> |
||||
#include <memory> |
||||
#include <string> |
||||
#include <utility> |
||||
#include <vector> |
||||
|
||||
|
||||
#ifdef HAVE_CAFFE |
||||
#include "caffe/caffe.hpp" |
||||
#endif |
||||
namespace cv { namespace text { |
||||
|
||||
inline bool fileExists (String filename) { |
||||
std::ifstream f(filename.c_str()); |
||||
return f.good(); |
||||
} |
||||
|
||||
//************************************************************************************
|
||||
//****************** TextImageClassifier *****************************************
|
||||
//************************************************************************************
|
||||
|
||||
//void TextImageClassifier::preprocess(const Mat& input,Mat& output)
|
||||
//{
|
||||
// this->preprocessor_->preprocess_(input,output,this->inputGeometry_,this->channelCount_);
|
||||
//}
|
||||
|
||||
//void TextImageClassifier::setPreprocessor(Ptr<ImagePreprocessor> ptr)
|
||||
//{
|
||||
// CV_Assert(!ptr.empty());
|
||||
// preprocessor_=ptr;
|
||||
//}
|
||||
|
||||
//Ptr<ImagePreprocessor> TextImageClassifier::getPreprocessor()
|
||||
//{
|
||||
// return preprocessor_;
|
||||
//}
|
||||
|
||||
|
||||
class DeepCNNTextDetectorCaffeImpl: public DeepCNNTextDetector{ |
||||
protected: |
||||
|
||||
|
||||
void process_(Mat inputImage, Mat &outputMat) |
||||
{ |
||||
// do forward pass and stores the output in outputMat
|
||||
//Process one image
|
||||
// CV_Assert(this->outputGeometry_.batchSize==1);
|
||||
//CV_Assert(outputMat.isContinuous());
|
||||
|
||||
#ifdef HAVE_CAFFE |
||||
net_->input_blobs()[0]->Reshape(1, this->inputChannelCount_,this->inputGeometry_.height,this->inputGeometry_.width); |
||||
net_->Reshape(); |
||||
float* inputBuffer=net_->input_blobs()[0]->mutable_cpu_data(); |
||||
float* inputData=inputBuffer; |
||||
|
||||
std::vector<Mat> input_channels; |
||||
Mat preprocessed; |
||||
// if the image have multiple color channels the input layer should be populated accordingly
|
||||
for (int channel=0;channel < this->inputChannelCount_;channel++){ |
||||
|
||||
cv::Mat netInputWraped(this->inputGeometry_.height, this->inputGeometry_.width, CV_32FC1, inputData); |
||||
input_channels.push_back(netInputWraped); |
||||
//input_data += width * height;
|
||||
inputData+=(this->inputGeometry_.height*this->inputGeometry_.width); |
||||
} |
||||
this->preprocess(inputImage,preprocessed); |
||||
split(preprocessed, input_channels); |
||||
|
||||
//preprocessed.copyTo(netInputWraped);
|
||||
|
||||
|
||||
this->net_->Forward(); |
||||
const float* outputNetData=net_->output_blobs()[0]->cpu_data(); |
||||
// const float* outputNetData1=net_->output_blobs()[1]->cpu_data();
|
||||
|
||||
|
||||
|
||||
|
||||
this->outputGeometry_.height = net_->output_blobs()[0]->height(); |
||||
this->outputGeometry_.width = net_->output_blobs()[0]->width(); |
||||
this->outputChannelCount_ = net_->output_blobs()[0]->channels(); |
||||
int outputSz = this->outputChannelCount_ * this->outputGeometry_.height * this->outputGeometry_.width; |
||||
outputMat.create(this->outputGeometry_.height , this->outputGeometry_.width,CV_32FC1); |
||||
float*outputMatData=(float*)(outputMat.data); |
||||
|
||||
memcpy(outputMatData,outputNetData,sizeof(float)*outputSz); |
||||
|
||||
|
||||
|
||||
#endif |
||||
} |
||||
|
||||
|
||||
|
||||
#ifdef HAVE_CAFFE |
||||
Ptr<caffe::Net<float> > net_; |
||||
#endif |
||||
//Size inputGeometry_;
|
||||
int minibatchSz_;//The existence of the assignment operator mandates this to be nonconst
|
||||
//int outputSize_;
|
||||
public: |
||||
DeepCNNTextDetectorCaffeImpl(const DeepCNNTextDetectorCaffeImpl& dn): |
||||
minibatchSz_(dn.minibatchSz_){ |
||||
outputGeometry_=dn.outputGeometry_; |
||||
inputGeometry_=dn.inputGeometry_; |
||||
//Implemented to supress Visual Studio warning "assignment operator could not be generated"
|
||||
#ifdef HAVE_CAFFE |
||||
this->net_=dn.net_; |
||||
#endif |
||||
} |
||||
DeepCNNTextDetectorCaffeImpl& operator=(const DeepCNNTextDetectorCaffeImpl &dn) |
||||
{ |
||||
#ifdef HAVE_CAFFE |
||||
this->net_=dn.net_; |
||||
#endif |
||||
this->setPreprocessor(dn.preprocessor_); |
||||
this->inputGeometry_=dn.inputGeometry_; |
||||
this->inputChannelCount_=dn.inputChannelCount_; |
||||
this->outputChannelCount_ = dn.outputChannelCount_; |
||||
// this->minibatchSz_=dn.minibatchSz_;
|
||||
//this->outputGeometry_=dn.outputSize_;
|
||||
this->preprocessor_=dn.preprocessor_; |
||||
this->outputGeometry_=dn.outputGeometry_; |
||||
return *this; |
||||
//Implemented to supress Visual Studio warning "assignment operator could not be generated"
|
||||
} |
||||
|
||||
DeepCNNTextDetectorCaffeImpl(String modelArchFilename, String modelWeightsFilename,Ptr<ImagePreprocessor> preprocessor, int maxMinibatchSz) |
||||
:minibatchSz_(maxMinibatchSz) |
||||
{ |
||||
|
||||
CV_Assert(this->minibatchSz_>0); |
||||
CV_Assert(fileExists(modelArchFilename)); |
||||
CV_Assert(fileExists(modelWeightsFilename)); |
||||
CV_Assert(!preprocessor.empty()); |
||||
this->setPreprocessor(preprocessor); |
||||
#ifdef HAVE_CAFFE |
||||
this->net_.reset(new caffe::Net<float>(modelArchFilename, caffe::TEST)); |
||||
CV_Assert(net_->num_inputs()==1); |
||||
CV_Assert(net_->num_outputs()==1); |
||||
CV_Assert(this->net_->input_blobs()[0]->channels()==1 |
||||
||this->net_->input_blobs()[0]->channels()==3); |
||||
// this->channelCount_=this->net_->input_blobs()[0]->channels();
|
||||
|
||||
|
||||
|
||||
this->net_->CopyTrainedLayersFrom(modelWeightsFilename); |
||||
|
||||
caffe::Blob<float>* inputLayer = this->net_->input_blobs()[0]; |
||||
|
||||
this->inputGeometry_.height = inputLayer->height(); |
||||
this->inputGeometry_.width = inputLayer->width(); |
||||
this->inputChannelCount_ = inputLayer->channels(); |
||||
//this->inputGeometry_.batchSize =1;
|
||||
|
||||
inputLayer->Reshape(this->minibatchSz_,this->inputChannelCount_,this->inputGeometry_.height, this->inputGeometry_.width); |
||||
net_->Reshape(); |
||||
this->outputChannelCount_ = net_->output_blobs()[0]->channels(); |
||||
//this->outputGeometry_.batchSize =1;
|
||||
this->outputGeometry_.height =net_->output_blobs()[0]->height(); |
||||
this->outputGeometry_.width = net_->output_blobs()[0]->width(); |
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#else |
||||
CV_Error(Error::StsError,"Caffe not available during compilation!"); |
||||
#endif |
||||
} |
||||
|
||||
|
||||
void detect(InputArray image, OutputArray Bbox_prob) |
||||
{ |
||||
Size outSize = Size(this->outputGeometry_.height,outputGeometry_.width); |
||||
Bbox_prob.create(outSize,CV_32F); // dummy initialization is it needed
|
||||
Mat outputMat = Bbox_prob.getMat(); |
||||
process_(image.getMat(),outputMat); |
||||
//copy back to outputArray
|
||||
outputMat.copyTo(Bbox_prob); |
||||
} |
||||
|
||||
|
||||
|
||||
//int getOutputSize()
|
||||
//{
|
||||
// return this->outputSize_;
|
||||
//}
|
||||
Size getOutputGeometry() |
||||
{ |
||||
return this->outputGeometry_; |
||||
} |
||||
Size getinputGeometry() |
||||
{ |
||||
return this->inputGeometry_; |
||||
} |
||||
|
||||
int getMinibatchSize() |
||||
{ |
||||
return this->minibatchSz_; |
||||
} |
||||
|
||||
int getBackend() |
||||
{ |
||||
return OCR_HOLISTIC_BACKEND_CAFFE; |
||||
} |
||||
void setPreprocessor(Ptr<ImagePreprocessor> ptr) |
||||
{ |
||||
CV_Assert(!ptr.empty()); |
||||
preprocessor_=ptr; |
||||
} |
||||
|
||||
Ptr<ImagePreprocessor> getPreprocessor() |
||||
{ |
||||
return preprocessor_; |
||||
} |
||||
}; |
||||
|
||||
|
||||
Ptr<DeepCNNTextDetector> DeepCNNTextDetector::create(String archFilename,String weightsFilename,Ptr<ImagePreprocessor> preprocessor,int minibatchSz,int backEnd) |
||||
{ |
||||
if(preprocessor.empty()) |
||||
{ |
||||
// create a custom preprocessor with rawval
|
||||
Ptr<ImagePreprocessor> preprocessor=ImagePreprocessor::createImageCustomPreprocessor(255); |
||||
// set the mean for the preprocessor
|
||||
|
||||
Mat textbox_mean(1,3,CV_8U); |
||||
textbox_mean.at<uchar>(0,0)=104; |
||||
textbox_mean.at<uchar>(0,1)=117; |
||||
textbox_mean.at<uchar>(0,2)=123; |
||||
preprocessor->set_mean(textbox_mean); |
||||
} |
||||
switch(backEnd){ |
||||
case OCR_HOLISTIC_BACKEND_CAFFE: |
||||
|
||||
return Ptr<DeepCNNTextDetector>(new DeepCNNTextDetectorCaffeImpl(archFilename, weightsFilename,preprocessor, minibatchSz)); |
||||
break; |
||||
case OCR_HOLISTIC_BACKEND_NONE: |
||||
default: |
||||
CV_Error(Error::StsError,"DeepCNN::create backend not implemented"); |
||||
return Ptr<DeepCNNTextDetector>(); |
||||
break; |
||||
} |
||||
return Ptr<DeepCNNTextDetector>(); |
||||
|
||||
} |
||||
|
||||
|
||||
Ptr<DeepCNNTextDetector> DeepCNNTextDetector::createTextBoxNet(String archFilename,String weightsFilename,int backEnd) |
||||
{ |
||||
|
||||
// create a custom preprocessor with rawval
|
||||
Ptr<ImagePreprocessor> preprocessor=ImagePreprocessor::createImageCustomPreprocessor(255); |
||||
// set the mean for the preprocessor
|
||||
|
||||
Mat textbox_mean(1,3,CV_8U); |
||||
textbox_mean.at<uchar>(0,0)=104; |
||||
textbox_mean.at<uchar>(0,1)=117; |
||||
textbox_mean.at<uchar>(0,2)=123; |
||||
preprocessor->set_mean(textbox_mean); |
||||
switch(backEnd){ |
||||
case OCR_HOLISTIC_BACKEND_CAFFE: |
||||
return Ptr<DeepCNNTextDetector>(new DeepCNNTextDetectorCaffeImpl(archFilename, weightsFilename,preprocessor, 100)); |
||||
break; |
||||
case OCR_HOLISTIC_BACKEND_NONE: |
||||
default: |
||||
CV_Error(Error::StsError,"DeepCNN::create backend not implemented"); |
||||
return Ptr<DeepCNNTextDetector>(); |
||||
break; |
||||
} |
||||
return Ptr<DeepCNNTextDetector>(); |
||||
|
||||
} |
||||
|
||||
void DeepCNNTextDetector::preprocess(const Mat& input,Mat& output) |
||||
{ |
||||
Size inputHtWd = Size(this->inputGeometry_.height,this->inputGeometry_.width); |
||||
this->preprocessor_->preprocess(input,output,inputHtWd,this->inputChannelCount_); |
||||
} |
||||
|
||||
//namespace cnn_config{
|
||||
//namespace caffe_backend{
|
||||
|
||||
//#ifdef HAVE_CAFFE
|
||||
|
||||
//bool getCaffeGpuMode()
|
||||
//{
|
||||
// return caffe::Caffe::mode()==caffe::Caffe::GPU;
|
||||
//}
|
||||
|
||||
//void setCaffeGpuMode(bool useGpu)
|
||||
//{
|
||||
// if(useGpu)
|
||||
// {
|
||||
// caffe::Caffe::set_mode(caffe::Caffe::GPU);
|
||||
// }else
|
||||
// {
|
||||
// caffe::Caffe::set_mode(caffe::Caffe::CPU);
|
||||
// }
|
||||
//}
|
||||
|
||||
//bool getCaffeAvailable()
|
||||
//{
|
||||
// return true;
|
||||
//}
|
||||
|
||||
//#else
|
||||
|
||||
//bool getCaffeGpuMode()
|
||||
//{
|
||||
// CV_Error(Error::StsError,"Caffe not available during compilation!");
|
||||
// return 0;
|
||||
//}
|
||||
|
||||
//void setCaffeGpuMode(bool useGpu)
|
||||
//{
|
||||
// CV_Error(Error::StsError,"Caffe not available during compilation!");
|
||||
// CV_Assert(useGpu==1);//Compilation directives force
|
||||
//}
|
||||
|
||||
//bool getCaffeAvailable(){
|
||||
// return 0;
|
||||
//}
|
||||
|
||||
//#endif
|
||||
|
||||
//}//namespace caffe
|
||||
//}//namespace cnn_config
|
||||
|
||||
} } //namespace text namespace cv
|
||||
|
Loading…
Reference in new issue