0%

Guide

macro expansions

  • #name ===> quote as strings “xxx”
  • ##name, name ===> xxx
  • a ## b ===> concatenate the preceding and following tokens.
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
26
27
28
29
30
31
32
// #name ===>  "xxx"
// name, ##name ===> xxx

// ##name ===> concatenate
// #name ===> quote as strings

// a ## b ===> concatenate the preceding and following tokens.


#define QUOTE(name) #name
#define CONCAT(x,y) x##y // x ## y space in ommited

#define MACRO(name) #name "foo"
#define MACRO2(name) name "foo"
#define MACRO3(name) ##name "foo"


#define CAT(a, ...) a ## __VA_ARGS__

#define IIF(c) CAT(IIF_, c)
#define IIF_0(t, ...) __VA_ARGS__
#define IIF_1(t, ...) t

void macro_demo()
{
QUOTE(test); // "test"
CONCAT(test, foo); // testfoo

MACRO(test); // "test" "foo"
MACRO2(test);// test "foo"
MACRO3(test);// test "foo"
}

macro function

define

1
2
3
#define SUM(a,b)  (a+b)

#define MYDEBUG(...) fprintf(stderr, ##__VA_ARGS__)

usage

1
2
int c = SUM(1,2);
MYDEBUG("%d,%d \n",1,2); /* Becomes fprintf(stderr,"%d,%d \n",1,2); */

with class object

define

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
class profiler {
public:
profiler(const char* func_name, unsigned int times = 1);
~profiler();

void start();
int stop();

private:
boost::posix_time::ptime pt1;
boost::posix_time::ptime pt2;
const char * m_func_name;
int m_times = 1;
};

#define ONCE_PROFILER() profiler _profiler_instance##__LINE__(__FUNCTION__)

#define BEGIN_PROFILE_ONE(name) profiler _profiler_##name(#name)
#define BEGIN_PROFILE_TIMES(name,times) profiler _profiler_##name(#name,times)

#define BEGIN_PROFILE(name,...) profiler _profiler_##name(#name, ##__VA_ARGS__)
#define END_PROFILE(name) _profiler_##name.stop()

usage

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
void main()
{

BEGIN_PROFILE(LoadImage);

load_image();

END_PROFILE(LoadImage);


BEGIN_PROFILE_TIMES(ProcessImageTimes, 100);
//BEGIN_PROFILE(ProcessImageTimes, 100);
for(int i=0; i<100;i++){
process_image();
}
END_PROFILE(ProcessImageTimes);

}

Reference

History

  • 20191010: created.

Guide

compile

1
2
3
4
5
6
git clone https://github.com/yse/easy_profiler.git
cd easy_profiler && mkdir build && cd build && cmake-gui ..

make -j8

sudo make install

usage

CMakeLists.txt

1
2
3
4
find_package(easy_profiler REQUIRED)
#easy_profiler_Dir /usr/local/lib/cmake/easy_profiler

target_link_libraries(my_application easy_profiler)

code

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
26
27
#include <easy/profiler.h>

void foo() {
EASY_FUNCTION(profiler::colors::Magenta); // Magenta block with name "foo"

EASY_BLOCK("Calculating sum"); // Begin block with default color == Amber100
int sum = 0;
for (int i = 0; i < 10; ++i) {
EASY_BLOCK("Addition", profiler::colors::Red); // Scoped red block (no EASY_END_BLOCK needed)
sum += i;
}
EASY_END_BLOCK; // End of "Calculating sum" block

EASY_BLOCK("Calculating multiplication", profiler::colors::Blue500); // Blue block
int mul = 1;
for (int i = 1; i < 11; ++i)
mul *= i;
//EASY_END_BLOCK; // This is not needed because all blocks are ended on destructor when closing braces met
}

void bar() {
EASY_FUNCTION(0xfff080aa); // Function block with custom ARGB color
}

void baz() {
EASY_FUNCTION(); // Function block with default color == Amber100
}

Reference

History

  • 20191010: created.

Guide

opencv

Matrix multiplication is where two matrices are multiplied directly. This operation multiplies matrix A of size [a x b] with matrix B of size [b x c] to produce matrix C of size [a x c].

In OpenCV it is achieved using the simple * operator:

C = A * B  // Aab * Bbc = Cac

Element-wise multiplication is where each pixel in the output matrix is formed by multiplying that pixel in matrix A by its corresponding entry in matrix B. The input matrices should be the same size, and the output will be the same size as well. This is achieved using the mul() function:

output = A.mul(B); // A B must have same size !!!

code

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
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
cv::Mat cv_matmul(const cv::Mat& A, const cv::Mat& B)
{
// matrix multipication m*k, k*n ===> m*n
cv::Mat C = A * B;
return C;
}

cv::Mat cv_mul(const cv::Mat& image, const cv::Mat& mask)
{
// element-wise multiplication output[i,j] = image[i,j] * mask[i,j]
cv::Mat output = image.mul(mask, 1.0); // m*n, m*n
return output;
}

cv::Mat cv_multiply3x1(const cv::Mat& mat3, const cv::Mat& mat1)
{
std::vector<cv::Mat> channels;
cv::split(mat3, channels);

std::vector<cv::Mat> result_channels;
for(int i = 0; i < channels.size(); i++)
{
result_channels.push_back(channels[i].mul(mat1));
}

cv::Mat result3;
cv::merge(result_channels, result3);
return result3;
}

cv::Mat cv_multiply3x3(const cv::Mat& mat3_a, const cv::Mat& mat3_b)
{
cv::Mat a;
cv::Mat b;
cv::Mat c;

std::vector<cv::Mat> a_channels;
std::vector<cv::Mat> b_channels;
std::vector<cv::Mat> c_channels;

cv::split(mat3_a, a_channels);
cv::split(mat3_b, b_channels);

for(int i = 0; i < a_channels.size() || b_channels.size(); i++)
{
c_channels.push_back(a_channels[i].mul(b_channels[i]));
}

cv::merge(c_channels, c);
return c;
}

numpy

numpy arrays are not matrices, and the standard operations *, +, -, / work element-wise on arrays.

Instead, you could try using numpy.matrix, and * will be treated like matrix multiplication.

code

Element-wise multiplication code

>>> img = np.array([1,2,3,4,5,6,7,8]).reshape(2,4)
>>> mask = np.array([1,1,1,1,0,0,0,0]).reshape(2,4)
>>> img * mask 
array([[1, 2, 3, 4],
       [0, 0, 0, 0]])
>>> 
>>> np.multiply(img, mask)
array([[1, 2, 3, 4],
       [0, 0, 0, 0]])

for numpy.array, *and multiply work element-wise

matrix multiplication code

>>> a = np.array([1,2,3,4,5,6,7,8]).reshape(2,4)
>>> b = np.array([1,1,1,1,0,0,0,0]).reshape(4,2)
>>> np.matmul(a,b)
array([[ 3,  3],
       [11, 11]])

>>> np.dot(a,b)
array([[ 3,  3],
       [11, 11]])

>>> a = np.matrix([1,2,3,4,5,6,7,8]).reshape(2,4)
>>> b = np.matrix([1,1,1,1,0,0,0,0]).reshape(4,2)
>>> a
matrix([[1, 2, 3, 4],
        [5, 6, 7, 8]])
>>> b
matrix([[1, 1],
        [1, 1],
        [0, 0],
        [0, 0]])
>>> a*b
matrix([[ 3,  3],
        [11, 11]])

>>> np.matmul(a,b)
matrix([[ 3,  3],
        [11, 11]])

for 2-dim, np.dot equals np.matmul
for numpy.array, np.matmul means matrix multiplication;
for numpy.matrix, * and np.matmul means matrix multiplication;

Reference

History

  • 20190109: created.

Guide

Jinja delimiters

The default Jinja delimiters are configured as follows:

{% ... %} for Statements
{{ ... }} for Expressions to print to the template output
 for Comments not included in the template output
#  ... ## for Line Statements

url_for static(css+image)

<link rel="stylesheet" type="text/css" href="{{ url_for('static', filename='bootstrap/bootstrap.min.css') }}">

<img src="{{ url_for('static', filename='images/1.PNG') }}" height="{{query_img_height}}" width="{{query_img_width}}">

You have by default the static endpoint for static files.

will be converted to

<link rel="stylesheet" type="text/css" href="/static/bootstrap/bootstrap.min.css">
<img src="/static/images/1.PNG" height="1799" width="896">

if we place js and css files in static folder, then we can use

<script src="static/js/lib/jquery-3.4.1.min.js"></script>

to replace

 <script src="{{ url_for('static', filename = 'js/lib/jquery-3.4.1.min.js') }}"></script>

url for static(pass image path)

<h1>Image  {{image_filename}}</h1>
<img src="{{ url_for('static', filename = image_filename) }}" height="{{query_img_height}}" width="{{query_img_width}}">

notice we do’t use

filename = {{image_filename}}

image_filename will be passed to html with value images/1.PNG

will be converted to

<h1>Image  images/1.PNG </h1>
<img src="/static/images/1.PNG" height="1799" width="896">

filter

{% set result_count = result_list | length %}

{{ index | string ) }}

filter: length, string

debug html

debug jinja2 html

url_for with params

python code

1
2
3
4
5
6
7
8
9
10
11
12
@app.route('/index')
@app.route('/')
def index():
return 'you are in the index page'


@app.route('/questions/<int:question_id>'):
#int has been used as a filter that only integer will be passed
# in the url otherwise it will give a 404 error

def find_question(question_id):
return ('you asked for question {0}'.format(question_id))

html page

1
2
3
4
5
6
<a href={{ url_for('index') }}>Index</a>
<a href = {{ url_for('find_question' ,question_id=1) }}>Question 1</a>

{% if kline_chart %}
<div class="chart">{{ kline_chart | safe }}</div>
{% endif %}

Realtime Video

index.html

1
<img src="{{ url_for('video_feed') }}" height="480" width="640">

main.py

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
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
#===================================================
outputFrame = None
lock = threading.Lock()

# initialize a flask object
app = Flask(__name__)

@app.route("/")
def index():
# return the rendered template
return render_template("index.html")

def generate():
# grab global references to the output frame and lock variables
global outputFrame, lock

# loop over frames from the output stream
while True:
# wait until the lock is acquired
with lock:
# check if the output frame is available, otherwise skip
# the iteration of the loop
if outputFrame is None:
continue

# encode the frame in JPEG format
(flag, encodedImage) = cv2.imencode(".jpg", outputFrame)

# ensure the frame was successfully encoded
if not flag:
continue

# yield the output frame in the byte format
yield(b'--frame\r\n' b'Content-Type: image/jpeg\r\n\r\n' +
bytearray(encodedImage) + b'\r\n')

@app.route("/video_feed")
def video_feed():
# return the response generated along with the specific media
# type (mime type)
return Response(generate(),
mimetype = "multipart/x-mixed-replace; boundary=frame")
#===================================================


# start the flask app
args = {"ip":"0.0.0.0","port":8888}
app.run(host=args["ip"], port=args["port"], debug=True,
threaded=True, use_reloader=False)

Example

index

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
26
27
28
29
30
# for web
from flask import Flask,Response,render_template

web_params = {
"query_key":"",
"query_segimg_filepath":"",
"query_segmask_filepath":"",
"query_img_height":0,
"query_img_width":0,
"result_list": []
}

# initialize a flask object
app = Flask(__name__)

_dir = os.path.dirname(os.path.abspath(__file__))
app.template_folder = os.path.join(_dir, "templates")
app.static_folder = os.path.join(_dir, "static")
print(app.template_folder)
print(app.static_folder)

@app.route("/")
def index():
global web_params
return render_template("search.html",**web_params)


# start the flask app
args = {"ip":"0.0.0.0","port":8888}
app.run(host=args["ip"], port=args["port"], debug=True,threaded=True, use_reloader=False)

index.html

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
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
<html>
<head>
<title>Query {{query_key}}</title>
</head>
<body>
<h1>Query Image {{ query_segimg_filepath }} </h1>

{#
<img src="{{ url_for('static', filename='images/1.PNG') }}"
height="30"
width="30">
#}

<img src="{{ url_for('static', filename = query_segimg_filepath) }}"
height="{{query_img_height}}"
width="{{query_img_width}}">
{#
<img src="{{ url_for('static', filename = query_segmask_filepath) }}"
height="{{query_img_height}}"
width="{{query_img_width}}">
#}

{% set result_count = result_list | length %}
<h1>Search Results #{{result_count}}</h1>

{% for i in range(0,result_count) %}
{% set item = result_list[i] %}
{% set segimg_filepath = item["segimg_filepath"] %}
{% set segmask_filepath = item["segmask_filepath"] %}

{% set img_height = item["height"] %}
{% set img_width = item["width"] %}

<h2>Top # {{i}} {{ segimg_filepath }}</h2>

<img src="{{ url_for('static', filename = segimg_filepath) }}" height="{{img_height}}" width="{{img_width}}">
{#
<img src="{{ url_for('static', filename = segmask_filepath) }}" height="{{img_height}}" width="{{img_width}}">
#}
{% endfor %}

</body>
</html>

Reference

History

  • 20191005: created.

Guide

MainForm

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
protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
{
//System.Console.WriteLine("ProcessCmdKey " + cur_image_id);

//capture up arrow key
if (keyData == Keys.Left)
{
//this.button_prev.PerformClick();
button_prev_click();

return true;
}
else if (keyData == Keys.Right)
{
//System.Console.WriteLine("Enter "+cur_image_id);

//this.button_ok.PerformClick();
button_ok_click();

return true;
}

return base.ProcessCmdKey(ref msg, keyData); // trigger 2 button_ok_click
}

TextBox

1
2
3
4
5
6
7
8
private void textBox_index_KeyDown(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.Enter)
{
//enter key is down
button_goto_click();
}
}

app.config

app.config.xml

1
2
3
4
5
6
7
8
9
10
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5.2" />
</startup>
<appSettings>
<add key="image_extension" value="png" />
<add key="output_filepath" value="./output.json" />
</appSettings>
</configuration>

usage

reference System.Configuration.dll

1
2
3
4
5
6
7
8
using System.Configuration;

private void init_config()
{
var appSettings = System.Configuration.ConfigurationManager.AppSettings;
string image_ext = "*."+ appSettings["image_extension"];
string output_filepath = appSettings["output_filepath"];
}

Reference

History

  • 20190919: created.

RAdam

usage

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import keras
import numpy as np
from keras_radam import RAdam

# Build toy model with RAdam optimizer
model = keras.models.Sequential()
model.add(keras.layers.Dense(input_shape=(17,), units=3))
model.compile(RAdam(), loss='mse')

# Generate toy data
x = np.random.standard_normal((4096 * 30, 17))
w = np.random.standard_normal((17, 3))
y = np.dot(x, w)

# Fit
model.fit(x, y, epochs=5)

use warmup

1
2
3
from keras_radam import RAdam

RAdam(total_steps=10000, warmup_proportion=0.1, min_lr=1e-5)

load custom optimizer

keras load model with custom optimizer with CustomObjectScope

error

when load model with custom optimizer, eg RAdam()

1
model = load_model("resnet50_radam_model.h5")

output error

ValueError: Unknown optimizer: RAdam

solution

1
2
3
4
5
6
7
from keras_radam import RAdam
from keras.utils import CustomObjectScope

with CustomObjectScope({'RAdam': RAdam()}):
best_model_filepath = "./checkpoint/best_model_efnb0.h5"
model = load_model(best_model_filepath)
model.save_weights("./checkpoint/weights_efnb0.h5")

Reference

History

  • 20190912: created.

Guide

About EfficientNet Models

params
flops

compared with resnet50, EfficientNet-B4 improves the top-1 accuracy from 76.3% of ResNet-50 to 82.6% (+6.3%), under similar FLOPS constraint.

Using Pretrained EfficientNet Checkpoints

b0-b7 top-1 on imagenet

Keras Models Performance

  • The top-k errors were obtained using Keras Applications with the TensorFlow backend on the 2012 ILSVRC ImageNet validation set and may slightly differ from the original ones.

The input size used was 224x224 for all models except NASNetLarge (331x331), InceptionV3 (299x299), InceptionResNetV2 (299x299), Xception (299x299),
EfficientNet-B0 (224x224), EfficientNet-B1 (240x240), EfficientNet-B2 (260x260), EfficientNet-B3 (300x300), EfficientNet-B4 (380x380), EfficientNet-B5 (456x456), EfficientNet-B6 (528x528), and EfficientNet-B7 (600x600).

notice

  • Top-1: single center crop, top-1 error
  • Top-5: single center crop, top-5 error
  • 10-5: ten crops (1 center + 4 corners and those mirrored ones), top-5 error
  • Size: rounded the number of parameters when include_top=True
  • Stem: rounded the number of parameters when include_top=False
Top-1 Top-5 10-5 Size Stem References
VGG16 28.732 9.950 8.834 138.4M 14.7M [paper] [tf-models]
VGG19 28.744 10.012 8.774 143.7M 20.0M [paper] [tf-models]
ResNet50 25.072 7.940 6.828 25.6M 23.6M [paper] [tf-models] [torch] [caffe]
ResNet101 23.580 7.214 6.092 44.7M 42.7M [paper] [tf-models] [torch] [caffe]
ResNet152 23.396 6.882 5.908 60.4M 58.4M [paper] [tf-models] [torch] [caffe]
ResNet50V2 24.040 6.966 5.896 25.6M 23.6M [paper] [tf-models] [torch]
ResNet101V2 22.766 6.184 5.158 44.7M 42.6M [paper] [tf-models] [torch]
ResNet152V2 21.968 5.838 4.900 60.4M 58.3M [paper] [tf-models] [torch]
ResNeXt50 22.260 6.190 5.410 25.1M 23.0M [paper] [torch]
ResNeXt101 21.270 5.706 4.842 44.3M 42.3M [paper] [torch]
InceptionV3 22.102 6.280 5.038 23.9M 21.8M [paper] [tf-models]
InceptionResNetV2 19.744 4.748 3.962 55.9M 54.3M [paper] [tf-models]
Xception 20.994 5.548 4.738 22.9M 20.9M [paper]
MobileNet(alpha=0.25) 48.418 24.208 21.196 0.5M 0.2M [paper] [tf-models]
MobileNet(alpha=0.50) 35.708 14.376 12.180 1.3M 0.8M [paper] [tf-models]
MobileNet(alpha=0.75) 31.588 11.758 9.878 2.6M 1.8M [paper] [tf-models]
MobileNet(alpha=1.0) 29.576 10.496 8.774 4.3M 3.2M [paper] [tf-models]
MobileNetV2(alpha=0.35) 39.914 17.568 15.422 1.7M 0.4M [paper] [tf-models]
MobileNetV2(alpha=0.50) 34.806 13.938 11.976 2.0M 0.7M [paper] [tf-models]
MobileNetV2(alpha=0.75) 30.468 10.824 9.188 2.7M 1.4M [paper] [tf-models]
MobileNetV2(alpha=1.0) 28.664 9.858 8.322 3.5M 2.3M [paper] [tf-models]
MobileNetV2(alpha=1.3) 25.320 7.878 6.728 5.4M 3.8M [paper] [tf-models]
MobileNetV2(alpha=1.4) 24.770 7.578 6.518 6.2M 4.4M [paper] [tf-models]
DenseNet121 25.028 7.742 6.522 8.1M 7.0M [paper] [torch]
DenseNet169 23.824 6.824 5.860 14.3M 12.6M [paper] [torch]
DenseNet201 22.680 6.380 5.466 20.2M 18.3M [paper] [torch]
NASNetLarge 17.502 3.996 3.412 93.5M 84.9M [paper] [tf-models]
NASNetMobile 25.634 8.146 6.758 7.7M 4.3M [paper] [tf-models]
EfficientNet-B0 22.810 6.508 5.858 5.3M 4.0M [paper] [tf-tpu]
EfficientNet-B1 20.866 5.552 5.050 7.9M 6.6M [paper] [tf-tpu]
EfficientNet-B2 19.820 5.054 4.538 9.2M 7.8M [paper] [tf-tpu]
EfficientNet-B3 18.422 4.324 3.902 12.3M 10.8M [paper] [tf-tpu]
EfficientNet-B4 17.040 3.740 3.344 19.5M 17.7M [paper] [tf-tpu]
EfficientNet-B5 16.298 3.290 3.114 30.6M 28.5M [paper] [tf-tpu]
EfficientNet-B6 15.918 3.102 2.916 43.3M 41.0M [paper] [tf-tpu]
EfficientNet-B7 15.570 3.160 2.906 66.7M 64.1M [paper] [tf-tpu]

Reference

History

  • 20190912: created.

Guide

Json.NET

  • JsonConvert.SerializeObject
  • JsonConvert.DeserializeObject

install

Use NuGet to download the package

"Project" -> "Manage NuGet packages" -> "Search for "newtonsoft json". -> click "install".

code

reference

using Newtonsoft.Json;

serialize collections

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
26
27
28
29
30
31
32
Product p1 = new Product
{
Name = "Product 1",
Price = 99.95m,
ExpiryDate = new DateTime(2000, 12, 29, 0, 0, 0, DateTimeKind.Utc),
};
Product p2 = new Product
{
Name = "Product 2",
Price = 12.50m,
ExpiryDate = new DateTime(2009, 7, 31, 0, 0, 0, DateTimeKind.Utc),
};

List<Product> products = new List<Product>();
products.Add(p1);
products.Add(p2);

string json = JsonConvert.SerializeObject(products, Formatting.Indented);
//[
// {
// "Name": "Product 1",
// "ExpiryDate": "2000-12-29T00:00:00Z",
// "Price": 99.95,
// "Sizes": null
// },
// {
// "Name": "Product 2",
// "ExpiryDate": "2009-07-31T00:00:00Z",
// "Price": 12.50,
// "Sizes": null
// }
//]

deserialize collections

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
string json = @"[
{
'Name': 'Product 1',
'ExpiryDate': '2000-12-29T00:00Z',
'Price': 99.95,
'Sizes': null
},
{
'Name': 'Product 2',
'ExpiryDate': '2009-07-31T00:00Z',
'Price': 12.50,
'Sizes': null
}
]";

List<Product> products = JsonConvert.DeserializeObject<List<Product>>(json);

Console.WriteLine(products.Count);
// 2

Product p1 = products[0];

Console.WriteLine(p1.Name);
// Product 1

serialize to json file

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public class Movie
{
public string Name { get; set; }
public int Year { get; set; }
}


Movie movie = new Movie
{
Name = "Bad Boys",
Year = 1995
};

// serialize JSON to a string and then write string to a file
File.WriteAllText(@"c:\movie.json", JsonConvert.SerializeObject(movie));

// serialize JSON directly to a file
using (StreamWriter file = File.CreateText(@"c:\movie.json"))
{
JsonSerializer serializer = new JsonSerializer();
serializer.Serialize(file, movie);
}

Reference

History

  • 20190910: created.

Guide

code

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
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
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
# import the necessary packages
from keras.preprocessing.image import ImageDataGenerator
from keras.preprocessing.image import img_to_array
from keras.preprocessing.image import load_img
import numpy as np
import argparse

from keras_util import *

# construct the argument parse and parse the arguments
ap = argparse.ArgumentParser()
ap.add_argument("-i", "--image", required=True,
help="path to the input image")
ap.add_argument("-o", "--output", required=True,
help="path to output directory to store augmentation examples")
ap.add_argument("-p", "--prefix", type=str, default="image",
help="output filename prefix")
args = vars(ap.parse_args())

# load the input image, convert it to a NumPy array, and then
# reshape it to have an extra dimension
print("[INFO] loading example image...")
target_size = None
#target_size=(224,224)
image = load_img(args["image"], target_size=target_size)
image = img_to_array(image)
image = np.expand_dims(image, axis=0) # 1,h,w,c

# construct the image generator for data augmentation then
# initialize the total number of images generated thus far

# preprocessing_function: The function will run after the image is resized and augmented.
# The function should take one argument:
# one image (Numpy tensor with rank 3),
# and should output a Numpy tensor with the same shape.


# for 1 image --->(424,640,3)--->aug---(424,640,3)--->preprocess_input--->(424,640,3)
# for 1 image --->resize--->(224,224,3)--->aug---(224,224,3)--->preprocess_input--->(224,224,3)
aug = ImageDataGenerator(preprocessing_function=resnet.preprocess_input,
rotation_range=30,
width_shift_range=0.1,
height_shift_range=0.1,
shear_range=0.2,
zoom_range=0.2,
horizontal_flip=True,
fill_mode="nearest")
total = 0

# construct the actual Python generator
print("[INFO] generating images...")
imageGen = aug.flow(image,
batch_size=1,
save_to_dir=args["output"],
save_prefix=args["prefix"],
save_format="png")

next_image = next(imageGen)
print(next_image.shape)
print(next_image[0, :5,:5,0])

# loop over examples from our image data augmentation generator
for image in imageGen:
# increment our counter
total += 1

# if we have reached 10 examples, break from the loop
if total == 10:
break

output

target_size = None:

1 image —>(424,640,3)—>aug—>(424,640,3)—>preprocess_input—>(424,640,3)

target_size = (224,224):

1 image —>resize—>(224,224,3)—>aug—>(224,224,3)—>preprocess_input—>(224,224,3)

Reference

History

  • 20190910: created.