Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit 1d150ac

Browse files
committed
Add Chapter11
1 parent 9a05f15 commit 1d150ac

34 files changed

+3087
-2
lines changed
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
QMAKE_CXX.INCDIRS = \
2+
/usr/include/c++/8 \
3+
/usr/include/arm-linux-gnueabihf/c++/8 \
4+
/usr/include/c++/8/backward \
5+
/usr/lib/gcc/arm-linux-gnueabihf/8/include \
6+
/usr/local/include \
7+
/usr/lib/gcc/arm-linux-gnueabihf/8/include-fixed \
8+
/usr/include/arm-linux-gnueabihf \
9+
/usr/include
10+
QMAKE_CXX.LIBDIRS = \
11+
/usr/lib/gcc/arm-linux-gnueabihf/8 \
12+
/usr/lib/arm-linux-gnueabihf \
13+
/usr/lib \
14+
/lib/arm-linux-gnueabihf \
15+
/lib
16+
QMAKE_CXX.QT_COMPILER_STDCXX = 201402L
17+
QMAKE_CXX.QMAKE_GCC_MAJOR_VERSION = 8
18+
QMAKE_CXX.QMAKE_GCC_MINOR_VERSION = 3
19+
QMAKE_CXX.QMAKE_GCC_PATCH_VERSION = 0
20+
QMAKE_CXX.COMPILER_MACROS = \
21+
QT_COMPILER_STDCXX \
22+
QMAKE_GCC_MAJOR_VERSION \
23+
QMAKE_GCC_MINOR_VERSION \
24+
QMAKE_GCC_PATCH_VERSION
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
######################################################################
2+
# Automatically generated by qmake (3.1) Mon Oct 21 18:12:42 2019
3+
######################################################################
4+
5+
QT += core gui
6+
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
7+
8+
TEMPLATE = app
9+
TARGET = CaffeWithCamera
10+
INCLUDEPATH += .
11+
12+
# The following define makes your compiler warn you if you use any
13+
# feature of Qt which has been marked as deprecated (the exact warnings
14+
# depend on your compiler). Please consult the documentation of the
15+
# deprecated API in order to know how to port your code away from it.
16+
DEFINES += QT_DEPRECATED_WARNINGS
17+
18+
# You can also make your code fail to compile if you use deprecated APIs.
19+
# In order to do so, uncomment the following line.
20+
# You can also select to disable deprecated APIs only up to a certain version of Qt.
21+
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0
22+
23+
# Input
24+
HEADERS += classification.h widget.h
25+
SOURCES += classification.cpp main.cpp widget.cpp
26+
27+
QMAKE_CXXFLAGS += -DCPU_ONLY `pkg-config --cflags opencv` -std=c++14 -I/usr/local/include -I/usr/local/Cellar/openblas/0.3.3/include -I/home/pi/caffe/build/install/include
28+
29+
LIBS += $$(LDFLAGS) `pkg-config --libs opencv` -lcaffe -L/usr/local/Cellar/caffe/1.0_6/lib -lglog -L/usr/local/Cellar/glog/0.3.5_3/lib -lboost_system -L/usr/local/lib -L/home/pi/caffe/build/lib
30+
31+
QMAKE_CXXFLAGS += -std=c++0x -DCPU_ONLY
32+
CONFIG += c++11

‎Chapter11/CaffeWithCamera/Makefile‎

Lines changed: 424 additions & 0 deletions
Large diffs are not rendered by default.
Lines changed: 220 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,220 @@
1+
#include "classification.h"
2+
3+
Classifier::Classifier( ) {
4+
/* 이미지 분류를 위한 데이터 파일을 설정한다. */
5+
const string model_file("/home/pi/caffe/models/SqueezeNet/SqueezeNet_v1.1/deploy.prototxt");
6+
const string trained_file("/home/pi/caffe/models/SqueezeNet/SqueezeNet_v1.1/squeezenet_v1.1.caffemodel");
7+
const string mean_file("/home/pi/caffe/data/ilsvrc12/imagenet_mean.binaryproto");
8+
const string label_file("/home/pi/caffe/data/ilsvrc12/synset_words.txt");
9+
10+
Caffe::set_mode(Caffe::CPU);
11+
12+
/* Load the network. */
13+
net_.reset(new Net<float>(model_file, TEST));
14+
net_->CopyTrainedLayersFrom(trained_file);
15+
16+
CHECK_EQ(net_->num_inputs(), 1) << "Network should have exactly one input.";
17+
CHECK_EQ(net_->num_outputs(), 1) << "Network should have exactly one output.";
18+
19+
Blob<float>* input_layer = net_->input_blobs()[0];
20+
num_channels_ = input_layer->channels();
21+
CHECK(num_channels_ == 3 || num_channels_ == 1)
22+
<< "Input layer should have 1 or 3 channels.";
23+
input_geometry_ = cv::Size(input_layer->width(), input_layer->height());
24+
25+
/* Load the binaryproto mean file. */
26+
SetMean(mean_file);
27+
28+
/* Load labels. */
29+
std::ifstream labels(label_file.c_str());
30+
CHECK(labels) << "Unable to open labels file " << label_file;
31+
string line;
32+
while (std::getline(labels, line))
33+
labels_.push_back(string(line));
34+
35+
Blob<float>* output_layer = net_->output_blobs()[0];
36+
CHECK_EQ(labels_.size(), output_layer->channels())
37+
<< "Number of labels is different from the output layer dimension.";
38+
}
39+
40+
/* 이미지를 분류하고 결과에 대한 문자열을 반환한다. */
41+
string Classifier::checkImage(const string& file)
42+
{
43+
string retString;
44+
std::cout << "---------- Prediction for" << file << "----------" << std::endl;
45+
cv::Mat img = cv::imread(file, -1); /* 이미지 파일을 읽어서 cv:Mat로 저장한다. */
46+
CHECK(!img.empty()) << "Unable to decode image" << file;
47+
std::vector<Prediction> predictions = Classify(img);
48+
49+
/* 선착순 N개의 예측에 대한 내용을 출력하고 문자열에 기록한다. */
50+
for (size_t i = 0; i < predictions.size(); ++i) {
51+
Prediction p = predictions[i];
52+
std::cout << std::fixed << std::setprecision(4) << p.second << "- \""
53+
<< p.first << "\"" << std::endl;
54+
retString += p.first;
55+
retString += '\n';
56+
}
57+
return retString;
58+
}
59+
60+
string Classifier::checkImage(cv::Mat& img)
61+
{
62+
string retString;
63+
CHECK(!img.empty()) << "Unable to decode image";
64+
std::vector<Prediction> predictions = Classify(img);
65+
std::cout << "---------- Prediction ----------" << std::endl;
66+
67+
/* 선착순 N개의 예측에 대한 내용을 출력하고 문자열에 기록한다. */
68+
for (size_t i = 0; i < predictions.size(); ++i) {
69+
Prediction p = predictions[i];
70+
std::cout << std::fixed << std::setprecision(4) << p.second << "- \""
71+
<< p.first << "\"" << std::endl;
72+
retString += p.first;
73+
retString += '\n';
74+
}
75+
76+
return retString;
77+
}
78+
79+
static bool PairCompare(const std::pair<float, int>& lhs,
80+
const std::pair<float, int>& rhs) {
81+
return lhs.first > rhs.first;
82+
}
83+
84+
/* Return the indices of the top N values of vector v. */
85+
static std::vector<int> Argmax(const std::vector<float>& v, int N) {
86+
std::vector<std::pair<float, int> > pairs;
87+
for (size_t i = 0; i < v.size(); ++i)
88+
pairs.push_back(std::make_pair(v[i], i));
89+
std::partial_sort(pairs.begin(), pairs.begin() + N, pairs.end(), PairCompare);
90+
91+
std::vector<int> result;
92+
for (int i = 0; i < N; ++i)
93+
result.push_back(pairs[i].second);
94+
return result;
95+
}
96+
97+
/* Return the top N predictions. */
98+
std::vector<Prediction> Classifier::Classify(const cv::Mat& img, int N) {
99+
std::vector<float> output = Predict(img);
100+
101+
N = std::min<int>(labels_.size(), N);
102+
std::vector<int> maxN = Argmax(output, N);
103+
std::vector<Prediction> predictions;
104+
for (int i = 0; i < N; ++i) {
105+
int idx = maxN[i];
106+
predictions.push_back(std::make_pair(labels_[idx], output[idx]));
107+
}
108+
109+
return predictions;
110+
}
111+
112+
/* Load the mean file in binaryproto format. */
113+
void Classifier::SetMean(const string& mean_file) {
114+
BlobProto blob_proto;
115+
ReadProtoFromBinaryFileOrDie(mean_file.c_str(), &blob_proto);
116+
117+
/* Convert from BlobProto to Blob<float> */
118+
Blob<float> mean_blob;
119+
mean_blob.FromProto(blob_proto);
120+
CHECK_EQ(mean_blob.channels(), num_channels_)
121+
<< "Number of channels of mean file doesn't match input layer.";
122+
123+
/* The format of the mean file is planar 32-bit float BGR or grayscale. */
124+
std::vector<cv::Mat> channels;
125+
float* data = mean_blob.mutable_cpu_data();
126+
for (int i = 0; i < num_channels_; ++i) {
127+
/* Extract an individual channel. */
128+
cv::Mat channel(mean_blob.height(), mean_blob.width(), CV_32FC1, data);
129+
channels.push_back(channel);
130+
data += mean_blob.height() * mean_blob.width();
131+
}
132+
133+
/* Merge the separate channels into a single image. */
134+
cv::Mat mean;
135+
cv::merge(channels, mean);
136+
137+
/* Compute the global mean pixel value and create a mean image
138+
* filled with this value. */
139+
cv::Scalar channel_mean = cv::mean(mean);
140+
mean_ = cv::Mat(input_geometry_, mean.type(), channel_mean);
141+
}
142+
143+
std::vector<float> Classifier::Predict(const cv::Mat& img) {
144+
Blob<float>* input_layer = net_->input_blobs()[0];
145+
input_layer->Reshape(1, num_channels_,
146+
input_geometry_.height, input_geometry_.width);
147+
/* Forward dimension change to all layers. */
148+
net_->Reshape();
149+
150+
std::vector<cv::Mat> input_channels;
151+
WrapInputLayer(&input_channels);
152+
153+
Preprocess(img, &input_channels);
154+
155+
net_->Forward();
156+
157+
/* Copy the output layer to a std::vector */
158+
Blob<float>* output_layer = net_->output_blobs()[0];
159+
const float* begin = output_layer->cpu_data();
160+
const float* end = begin + output_layer->channels();
161+
return std::vector<float>(begin, end);
162+
}
163+
164+
/* Wrap the input layer of the network in separate cv::Mat objects
165+
* (one per channel). This way we save one memcpy operation and we
166+
* don't need to rely on cudaMemcpy2D. The last preprocessing
167+
* operation will write the separate channels directly to the input
168+
* layer. */
169+
void Classifier::WrapInputLayer(std::vector<cv::Mat>* input_channels) {
170+
Blob<float>* input_layer = net_->input_blobs()[0];
171+
172+
int width = input_layer->width();
173+
int height = input_layer->height();
174+
float* input_data = input_layer->mutable_cpu_data();
175+
for (int i = 0; i < input_layer->channels(); ++i) {
176+
cv::Mat channel(height, width, CV_32FC1, input_data);
177+
input_channels->push_back(channel);
178+
input_data += width * height;
179+
}
180+
}
181+
182+
void Classifier::Preprocess(const cv::Mat& img,
183+
std::vector<cv::Mat>* input_channels) {
184+
/* Convert the input image to the input image format of the network. */
185+
cv::Mat sample;
186+
if (img.channels() == 3 && num_channels_ == 1)
187+
cv::cvtColor(img, sample, cv::COLOR_BGR2GRAY);
188+
else if (img.channels() == 4 && num_channels_ == 1)
189+
cv::cvtColor(img, sample, cv::COLOR_BGRA2GRAY);
190+
else if (img.channels() == 4 && num_channels_ == 3)
191+
cv::cvtColor(img, sample, cv::COLOR_BGRA2BGR);
192+
else if (img.channels() == 1 && num_channels_ == 3)
193+
cv::cvtColor(img, sample, cv::COLOR_GRAY2BGR);
194+
else
195+
sample = img;
196+
197+
cv::Mat sample_resized;
198+
if (sample.size() != input_geometry_)
199+
cv::resize(sample, sample_resized, input_geometry_);
200+
else
201+
sample_resized = sample;
202+
203+
cv::Mat sample_float;
204+
if (num_channels_ == 3)
205+
sample_resized.convertTo(sample_float, CV_32FC3);
206+
else
207+
sample_resized.convertTo(sample_float, CV_32FC1);
208+
209+
cv::Mat sample_normalized;
210+
cv::subtract(sample_float, mean_, sample_normalized);
211+
212+
/* This operation will write the separate BGR planes directly to the
213+
* input layer of the network because it is wrapped by the cv::Mat
214+
* objects in input_channels. */
215+
cv::split(sample_normalized, *input_channels);
216+
217+
CHECK(reinterpret_cast<float*>(input_channels->at(0).data)
218+
== net_->input_blobs()[0]->cpu_data())
219+
<< "Input channels are not wrapping the input layer of the network.";
220+
}
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
#ifndef CLASSIFICATION_H
2+
#define CLASSIFICATION_H
3+
4+
#include <caffe/caffe.hpp>
5+
#include <opencv2/core/core.hpp>
6+
#include <opencv2/highgui/highgui.hpp>
7+
#include <opencv2/imgproc/imgproc.hpp>
8+
#include <algorithm>
9+
#include <iosfwd>
10+
#include <memory>
11+
#include <string>
12+
#include <utility>
13+
#include <vector>
14+
15+
using namespace caffe; // NOLINT(build/namespaces)
16+
using std::string;
17+
18+
/* Pair (label, confidence) representing a prediction. */
19+
typedef std::pair<string, float> Prediction;
20+
21+
class Classifier {
22+
public:
23+
Classifier(); /* 생성자 */
24+
string checkImage(const string& file); /* 이미지의 분류를 위한 메소드 */
25+
string checkImage(cv::Mat& img);
26+
27+
std::vector<Prediction> Classify(const cv::Mat& img, int N = 5);
28+
29+
private:
30+
void SetMean(const string& mean_file);
31+
32+
std::vector<float> Predict(const cv::Mat& img);
33+
34+
void WrapInputLayer(std::vector<cv::Mat>* input_channels);
35+
36+
void Preprocess(const cv::Mat& img,
37+
std::vector<cv::Mat>* input_channels);
38+
39+
private:
40+
shared_ptr<Net<float> > net_;
41+
cv::Size input_geometry_;
42+
int num_channels_;
43+
cv::Mat mean_;
44+
std::vector<string> labels_;
45+
};
46+
47+
#endif /* CLASSIFICATION_H */

‎Chapter11/CaffeWithCamera/main.cpp‎

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
#include <QApplication> /* QApplication 클래스를 위한 헤더 파일 */
2+
3+
#include "widget.h"
4+
5+
int main(int argc, char** argv)
6+
{
7+
QApplication app(argc, argv);
8+
9+
Widget w;
10+
w.show();
11+
12+
return app.exec();
13+
}

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /