Tsyxxxka 4 years ago
parent 8b2e8a4def
commit 47ab8908bf

16
.gitignore vendored

@ -0,0 +1,16 @@
# Python virtual environment
/venv/
# Vue node.js node_modules
/static/.idea/
/static/node_modules/
/static/dist/
# Python users' pictures
/apps/assets/
!/apps/assets/.gitkeep
# Python users' result-pictures
/apps/results/
!/apps/results/.gitkeep
.pyc
__pycache__

8
.idea/.gitignore vendored

@ -0,0 +1,8 @@
# Default ignored files
/shelf/
/workspace.xml
# Editor-based HTTP Client requests
/httpRequests/
# Datasource local storage ignored files
/dataSources/
/dataSources.local.xml

@ -0,0 +1,14 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="PYTHON_MODULE" version="4">
<component name="NewModuleRootManager">
<content url="file://$MODULE_DIR$">
<excludePattern pattern=".idea" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
<component name="PyDocumentationSettings">
<option name="format" value="PLAIN" />
<option name="myDocStringFormat" value="Plain" />
</component>
</module>

@ -0,0 +1,6 @@
<component name="InspectionProjectProfileManager">
<profile version="1.0">
<option name="myName" value="Project Default" />
<inspection_tool class="Eslint" enabled="true" level="WARNING" enabled_by_default="true" />
</profile>
</component>

@ -0,0 +1,6 @@
<component name="InspectionProjectProfileManager">
<settings>
<option name="USE_PROJECT_PROFILE" value="false" />
<version value="1.0" />
</settings>
</component>

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectRootManager" version="2" project-jdk-name="Python 3.8 (ImgProcess)" project-jdk-type="Python SDK" />
</project>

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/.idea/ImgProcess.iml" filepath="$PROJECT_DIR$/.idea/ImgProcess.iml" />
</modules>
</component>
</project>

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="PySciProjectComponent">
<option name="PY_SCI_VIEW_SUGGESTED" value="true" />
</component>
</project>

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$" vcs="Git" />
</component>
</project>

@ -1,2 +0,0 @@
# image_processing_system_with_style_transfer

BIN
apps/.DS_Store vendored

Binary file not shown.

@ -0,0 +1,16 @@
from flask import Flask
from apps.views import testview, basicFuncViews, histogramViews, segmentationViews, smoothSharpenViews, repairViews, \
morphologicalViews, filesViews, styleTransferViews
app = Flask(__name__)
app.config['JSON_AS_ASCII'] = False
app.register_blueprint(testview.app)
app.register_blueprint(filesViews.app)
app.register_blueprint(basicFuncViews.app)
app.register_blueprint(histogramViews.app)
app.register_blueprint(segmentationViews.app)
app.register_blueprint(smoothSharpenViews.app)
app.register_blueprint(morphologicalViews.app)
app.register_blueprint(repairViews.app)
app.register_blueprint(styleTransferViews.app)

@ -0,0 +1,201 @@
#coding=utf8
import cv2
import numpy as np
from apps.service import utils
def graying(img_name, result_name):
img_path = 'apps/assets/' + img_name
result_path = 'apps/results/' + result_name
img = cv2.imread(img_path, 1)
result = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
cv2.imwrite(result_path, result)
return 1
def thresholding(img_name, result_name):
img_path = 'apps/assets/' + img_name
result_path = 'apps/results/' + result_name
img = cv2.imread(img_path, 1)
img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
ret, result = cv2.threshold(img, 127, 255, cv2.THRESH_BINARY)
cv2.imwrite(result_path, result)
return 1
def logical_and(img_name1, img_name2, result_name):
img_path1 = 'apps/assets/' + img_name1
img_path2 = 'apps/assets/' + img_name2
result_path = 'apps/results/' + result_name
img1 = cv2.imread(img_path1, 0)
img2 = cv2.imread(img_path2, 0)
img1, img2 = utils.img_expand(img1, img2)
result = img1 & img2
cv2.imwrite(result_path, result)
return 1
def logical_or(img_name1, img_name2, result_name):
img_path1 = 'apps/assets/' + img_name1
img_path2 = 'apps/assets/' + img_name2
result_path = 'apps/results/' + result_name
img1 = cv2.imread(img_path1, 0)
img2 = cv2.imread(img_path2, 0)
img1, img2 = utils.img_expand(img1, img2)
result = img1 | img2
cv2.imwrite(result_path, result)
return 1
def logical_not(img_name, result_name):
img_path = 'apps/assets/' + img_name
result_path = 'apps/results/' + result_name
img = cv2.imread(img_path, 0)
result = ~img
cv2.imwrite(result_path, result)
return 1
def add(img_name1, img_name2, result_name):
img_path1 = 'apps/assets/' + img_name1
img_path2 = 'apps/assets/' + img_name2
result_path = 'apps/results/' + result_name
img1 = cv2.imread(img_path1, 1)
img2 = cv2.imread(img_path2, 1)
img1, img2 = utils.img_expand(img1, img2)
result = cv2.add(img1, img2)
cv2.imwrite(result_path, result)
return 1
def subtract(img_name1, img_name2, result_name):
img_path1 = 'apps/assets/' + img_name1
img_path2 = 'apps/assets/' + img_name2
result_path = 'apps/results/' + result_name
img1 = cv2.imread(img_path1, 1)
img2 = cv2.imread(img_path2, 1)
img1, img2 = utils.img_expand(img1, img2)
result = cv2.subtract(img1, img2)
cv2.imwrite(result_path, result)
return 1
def multiply(img_name1, img_name2, result_name):
img_path1 = 'apps/assets/' + img_name1
img_path2 = 'apps/assets/' + img_name2
result_path = 'apps/results/' + result_name
img1 = cv2.imread(img_path1, 1)
img2 = cv2.imread(img_path2, 1)
img1, img2 = utils.img_expand(img1, img2)
result = cv2.multiply(img1, img2)
cv2.imwrite(result_path, result)
return 1
def divide(img_name1, img_name2, result_name):
img_path1 = 'apps/assets/' + img_name1
img_path2 = 'apps/assets/' + img_name2
result_path = 'apps/results/' + result_name
img1 = cv2.imread(img_path1, 1)
img2 = cv2.imread(img_path2, 1)
img1, img2 = utils.img_expand(img1, img2)
result = cv2.divide(img1, img2)
cv2.imwrite(result_path, result)
return 1
def flip(img_name, result_name, fli_choi):
img_path = 'apps/assets/' + img_name
result_path = 'apps/results/' + result_name
img = cv2.imread(img_path, 1)
if fli_choi == 'horizontal':
result = cv2.flip(img, 1)
elif fli_choi == 'vertical':
result = cv2.flip(img, 0)
elif fli_choi == 'diagonal':
result = cv2.flip(img, -1)
else:
return 2
cv2.imwrite(result_path, result)
return 1
def move(img_name, result_name, move_x, move_y):
img_path = 'apps/assets/' + img_name
result_path = 'apps/results/' + result_name
try:
move_x = int(move_x)
move_y = int(move_y)
except ValueError:
return 2
img = cv2.imread(img_path, 1)
pix_M = np.float32([[1, 0, move_x], [0, 1, move_y]])
img_height, img_width, img_channel = img.shape
result = cv2.warpAffine(img, pix_M, (img_width, img_height))
cv2.imwrite(result_path, result)
return 1
def rotate(img_name, result_name, angle):
img_path = 'apps/assets/' + img_name
result_path = 'apps/results/' + result_name
try:
angle = int(angle)
except ValueError:
return 2
img = cv2.imread(img_path, 1)
result = utils.rotate(img, angle)
cv2.imwrite(result_path, result)
return 1
def resize(img_name, result_name, size_x, size_y):
img_path = 'apps/assets/' + img_name
result_path = 'apps/results/' + result_name
try:
size_x = float(size_x)
size_y = float(size_y)
except ValueError:
return 2
if (size_x <= 0) or (size_y <= 0):
return 2
img = cv2.imread(img_path, 1)
result = cv2.resize(img, (0, 0), fx=size_x, fy=size_y, interpolation=cv2.INTER_LINEAR)
cv2.imwrite(result_path, result)
return 1

@ -0,0 +1,26 @@
#coding=utf8
import os
from flask import send_file, jsonify
def resp_file_upload(file):
file_name = file.filename
file_path = 'apps/assets/' + file_name
if os.path.exists(file_path):
return {'code': 0, 'msg': '同名文件已存在,保存失败'}
else:
file.save(file_path)
return {'code': 1, 'msg': '保存文件成功'}
def resp_file_download(requ_data):
file_name = requ_data['file_name']
file_path = 'apps/results/' + file_name
if os.path.exists(file_path):
return send_file(file_path, as_attachment=True)
else:
return jsonify({
'msg': '文件不存在',
})

@ -0,0 +1,38 @@
#coding=utf8
import cv2
from matplotlib import pyplot as plt
def gray_histogram(img_name, result_name):
img_path = 'apps/assets/' + img_name
result_path = 'apps/results/' + result_name
img = cv2.imread(img_path, 0)
plt.subplot(121)
plt.imshow(img, "gray")
plt.subplot(122)
hist = cv2.calcHist([img], [0], None, [256], [0, 255])
plt.plot(hist)
plt.xlim([0, 255])
plt.savefig(result_path)
return 1
def bgr_histogram(img_name, result_name):
img_path = 'apps/assets/' + img_name
result_path = 'apps/results/' + result_name
img = cv2.imread(img_path)
color = ["r", "g", "b"]
img_b, img_g, img_r = cv2.split(img)
img = cv2.merge([img_r, img_g, img_b])
plt.subplot(121)
plt.imshow(img)
plt.subplot(122)
for index, c in enumerate(color):
hist = cv2.calcHist([img], [index], None, [256], [0, 255])
plt.plot(hist, color=c)
plt.xlim([0, 255])
plt.savefig(result_path)
return 1

@ -0,0 +1,59 @@
# -*- coding: utf-8 -*-
# @File : model.py
# @Author : AaronJny
# @Time : 2020/03/13
# @Desc :
import typing
import tensorflow as tf
from apps.service import settings
def get_vgg19_model(layers):
"""
创建并初始化vgg19模型
:return:
"""
# 加载imagenet上预训练的vgg19
vgg = tf.keras.applications.VGG19(include_top=False, weights='imagenet')
# 提取需要被用到的vgg的层的output
outputs = [vgg.get_layer(layer).output for layer in layers]
# 使用outputs创建新的模型
model = tf.keras.Model([vgg.input, ], outputs)
# 锁死参数,不进行训练
model.trainable = False
return model
class NeuralStyleTransferModel(tf.keras.Model):
def __init__(self, content_layers: typing.Dict[str, float] = settings.CONTENT_LAYERS,
style_layers: typing.Dict[str, float] = settings.STYLE_LAYERS):
super(NeuralStyleTransferModel, self).__init__()
# 内容特征层字典 Dict[层名,加权系数]
self.content_layers = content_layers
# 风格特征层
self.style_layers = style_layers
# 提取需要用到的所有vgg层
layers = list(self.content_layers.keys()) + list(self.style_layers.keys())
# 创建layer_name到output索引的映射
self.outputs_index_map = dict(zip(layers, range(len(layers))))
# 创建并初始化vgg网络
self.vgg = get_vgg19_model(layers)
def call(self, inputs, training=None, mask=None):
"""
前向传播
:return
typing.Dict[str,typing.List[outputs,加权系数]]
"""
outputs = self.vgg(inputs)
# 分离内容特征层和风格特征层的输出,方便后续计算 typing.List[outputs,加权系数]
content_outputs = []
for layer, factor in self.content_layers.items():
content_outputs.append((outputs[self.outputs_index_map[layer]][0], factor))
style_outputs = []
for layer, factor in self.style_layers.items():
style_outputs.append((outputs[self.outputs_index_map[layer]][0], factor))
# 以字典的形式返回输出
return {'content': content_outputs, 'style': style_outputs}

@ -0,0 +1,104 @@
#coding=utf8
import cv2
import numpy as np
from apps.service import utils
def erode(img_name, result_name, kernel_type, kernel_size):
img_path = 'apps/assets/' + img_name
result_path = 'apps/results/' + result_name
try:
kernel_size = int(kernel_size)
except ValueError:
return 2
if (kernel_size <= 0) or (kernel_size % 2 == 0):
return 2
img = cv2.imread(img_path, cv2.IMREAD_UNCHANGED)
if kernel_type == 'cross':
kernel = cv2.cv2.getStructuringElement(cv2.MORPH_CROSS, (kernel_size, kernel_size))
elif kernel_type == 'rectangle':
kernel = cv2.cv2.getStructuringElement(cv2.MORPH_RECT, (kernel_size, kernel_size))
else:
return 2
result = cv2.erode(img, kernel)
cv2.imwrite(result_path, result)
return 1
def dilate(img_name, result_name, kernel_type, kernel_size):
img_path = 'apps/assets/' + img_name
result_path = 'apps/results/' + result_name
try:
kernel_size = int(kernel_size)
except ValueError:
return 2
if (kernel_size <= 0) or (kernel_size % 2 == 0):
return 2
img = cv2.imread(img_path, cv2.IMREAD_UNCHANGED)
if kernel_type == 'cross':
kernel = cv2.cv2.getStructuringElement(cv2.MORPH_CROSS, (kernel_size, kernel_size))
elif kernel_type == 'rectangle':
kernel = cv2.cv2.getStructuringElement(cv2.MORPH_RECT, (kernel_size, kernel_size))
else:
return 2
result = cv2.dilate(img, kernel)
cv2.imwrite(result_path, result)
return 1
def mor_open(img_name, result_name, kernel_type, kernel_size):
img_path = 'apps/assets/' + img_name
result_path = 'apps/results/' + result_name
try:
kernel_size = int(kernel_size)
except ValueError:
return 2
if (kernel_size <= 0) or (kernel_size % 2 == 0):
return 2
img = cv2.imread(img_path, cv2.IMREAD_UNCHANGED)
if kernel_type == 'cross':
kernel = cv2.cv2.getStructuringElement(cv2.MORPH_CROSS, (kernel_size, kernel_size))
elif kernel_type == 'rectangle':
kernel = cv2.cv2.getStructuringElement(cv2.MORPH_RECT, (kernel_size, kernel_size))
else:
return 2
result = cv2.morphologyEx(img, cv2.MORPH_OPEN, kernel)
cv2.imwrite(result_path, result)
return 1
def mor_close(img_name, result_name, kernel_type, kernel_size):
img_path = 'apps/assets/' + img_name
result_path = 'apps/results/' + result_name
try:
kernel_size = int(kernel_size)
except ValueError:
return 2
if (kernel_size <= 0) or (kernel_size % 2 == 0):
return 2
img = cv2.imread(img_path, cv2.IMREAD_UNCHANGED)
if kernel_type == 'cross':
kernel = cv2.cv2.getStructuringElement(cv2.MORPH_CROSS, (kernel_size, kernel_size))
elif kernel_type == 'rectangle':
kernel = cv2.cv2.getStructuringElement(cv2.MORPH_RECT, (kernel_size, kernel_size))
else:
return 2
result = cv2.morphologyEx(img, cv2.MORPH_CLOSE, kernel)
cv2.imwrite(result_path, result)
return 1

Binary file not shown.

After

Width:  |  Height:  |  Size: 88 KiB

@ -0,0 +1,292 @@
#coding=utf8
import sys
import cv2
import numpy as np
from apps.service import utils
def gauss_noise(img_name, result_name):
img_path = 'apps/assets/' + img_name
result_path = 'apps/results/' + result_name
img = cv2.imread(img_path)
image = np.array(img / 255, dtype=float)
noise = np.random.normal(0, 0.1, image.shape)
out = image + noise
out = np.clip(out, 0.0, 1.0)
out = np.uint8(out * 255)
cv2.imwrite(result_path, out)
return 1
def sault_pepper_noise(img_name, result_name, ran_x1, ran_y1, ran_x2, ran_y2):
img_path = 'apps/assets/' + img_name
result_path = 'apps/results/' + result_name
try:
if ran_y1 == "MAX":
ran_y1 = sys.maxsize
if ran_y2 == "MAX":
ran_y2 = sys.maxsize
ran_x1 = int(ran_x1)
ran_y1 = int(ran_y1)
ran_x2 = int(ran_x2)
ran_y2 = int(ran_y2)
except ValueError:
return 2
if (ran_x1 < 0) or (ran_y1 < 0) or (ran_x2 < 0) or (ran_y2 < 0):
return 2
if ran_x1 >= ran_y1:
ran_x1, ran_y1 = utils.swap(ran_x1, ran_y1)
if ran_x2 >= ran_y2:
ran_x2, ran_y2 = utils.swap(ran_x2, ran_y2)
img = cv2.imread(img_path, 0)
out = np.zeros(img.shape, np.uint8)
for i in range(img.shape[0]):
for j in range(img.shape[1]):
if ran_x1 < img[i][j] < ran_y1:
# 添加胡椒噪声
out[i][j] = 0
elif ran_x2 < img[i][j] < ran_y2:
# 添加食盐噪声
out[i][j] = 255
else:
# 不添加噪声
out[i][j] = img[i][j]
cv2.imwrite(result_path, out)
return 1
def arithmetic_average_filter(img_name, result_name, filter_size_p, filter_size_q ):
img_path = 'apps/assets/' + img_name
result_path = 'apps/results/' + result_name
try:
filter_size_p = int(filter_size_p)
filter_size_q = int(filter_size_q)
except ValueError:
return 2
if (filter_size_p <= 0) or (filter_size_q <= 0):
return 2
if ((filter_size_p % 2) == 0) or ((filter_size_q % 2) == 0):
return 2
p = int(filter_size_p / 2)
q = int(filter_size_q / 2)
img = cv2.imread(img_path, 0)
out = np.zeros(img.shape, np.uint8)
for i in range(img.shape[0]):
for j in range(img.shape[1]):
sum = 0
for m in range(-p, p + 1):
for n in range(-q, q + 1):
if 0 <= i + m < img.shape[0] and 0 <= j + n < img.shape[1]:
sum += img[i + m][j + n]
out[i][j] = int(sum / (filter_size_p * filter_size_q))
cv2.imwrite(result_path, out)
return 1
def geometric_average_filter(img_name, result_name, filter_size_p, filter_size_q):
img_path = 'apps/assets/' + img_name
result_path = 'apps/results/' + result_name
try:
filter_size_p = int(filter_size_p)
filter_size_q = int(filter_size_q)
except ValueError:
return 2
if (filter_size_p <= 0) or (filter_size_q <= 0):
return 2
if ((filter_size_p % 2) == 0) or ((filter_size_q % 2) == 0):
return 2
p = int(filter_size_p / 2)
q = int(filter_size_q / 2)
img = cv2.imread(img_path, 0)
out = np.zeros(img.shape, np.uint8)
for i in range(img.shape[0]):
for j in range(img.shape[1]):
mul = 1
for m in range(-p, p + 1):
for n in range(-q, q + 1):
if 0 <= i + m < img.shape[0] and 0 <= j + n < img.shape[1]:
mul *= img[i + m][j + n]
out[i][j] = int(pow(mul, float (1 / (filter_size_p * filter_size_q))))
cv2.imwrite(result_path, out)
return 1
def harmonic_average_filter(img_name, result_name, filter_size_p, filter_size_q):
img_path = 'apps/assets/' + img_name
result_path = 'apps/results/' + result_name
try:
filter_size_p = int(filter_size_p)
filter_size_q = int(filter_size_q)
except ValueError:
return 2
if (filter_size_p <= 0) or (filter_size_q <= 0):
return 2
if ((filter_size_p % 2) == 0) or ((filter_size_q % 2) == 0):
return 2
p = int(filter_size_p / 2)
q = int(filter_size_q / 2)
img = cv2.imread(img_path, 0)
out = np.zeros(img.shape, np.uint8)
for i in range(img.shape[0]):
for j in range(img.shape[1]):
harm = 0.0
for m in range(-p, p + 1):
for n in range(-q, q + 1):
if 0 <= i + m < img.shape[0] and 0 <= j + n < img.shape[1]:
harm += 1 / img[i + m][j + n]
out[i][j] = int((filter_size_p * filter_size_q) / harm)
cv2.imwrite(result_path, out)
return 1
def min_filter(img_name, result_name):
img_path = 'apps/assets/' + img_name
result_path = 'apps/results/' + result_name
img = cv2.imread(img_path, 0)
out = np.zeros(img.shape, np.uint8)
array = []
for i in range(img.shape[0]):
for j in range(img.shape[1]):
array.clear()
for m in range(-1, 2):
for n in range(-1, 2):
if 0 <= i + m < img.shape[0] and 0 <= j + n < img.shape[1]:
array.append(img[i + m][j + n])
res_array = utils.order_desc(array)
res_array_leng = len(res_array)
out[i][j] = res_array[res_array_leng - 1]
cv2.imwrite(result_path, out)
return 1
def max_filter(img_name, result_name):
img_path = 'apps/assets/' + img_name
result_path = 'apps/results/' + result_name
img = cv2.imread(img_path, 0)
out = np.zeros(img.shape, np.uint8)
array = []
for i in range(img.shape[0]):
for j in range(img.shape[1]):
array.clear()
for m in range(-1, 2):
for n in range(-1, 2):
if 0 <= i + m < img.shape[0] and 0 <= j + n < img.shape[1]:
array.append(img[i + m][j + n])
res_array = utils.order_desc(array)
res_array_leng = len(res_array)
out[i][j] = res_array[0]
cv2.imwrite(result_path, out)
return 1
def median_filter(img_name, result_name):
img_path = 'apps/assets/' + img_name
result_path = 'apps/results/' + result_name
img = cv2.imread(img_path, 0)
out = np.zeros(img.shape, np.uint8)
array = []
for i in range(img.shape[0]):
for j in range(img.shape[1]):
array.clear()
for m in range(-1, 2):
for n in range(-1, 2):
if 0 <= i + m < img.shape[0] and 0 <= j + n < img.shape[1]:
array.append(img[i + m][j + n])
res_array = utils.order_desc(array)
res_array_leng = len(res_array)
out[i][j] = res_array[int(res_array_leng / 2)]
cv2.imwrite(result_path, out)
return 1
def range_filter(img_name, result_name, min, max, color):
img_path = 'apps/assets/' + img_name
result_path = 'apps/results/' + result_name
try:
if max == "MAX":
max = sys.maxsize
min = int(min)
max = int(max)
except ValueError:
return 2
if (min < 0) or (max < 0):
return 2
if min >= max:
min, max = utils.swap(min, max)
img = cv2.imread(img_path, 0)
out = np.zeros(img.shape, np.uint8)
array = []
for i in range(img.shape[0]):
for j in range(img.shape[1]):
# 滤波器内像素值的和
array.clear()
if min < img[i][j] < max:
out[i][j] = img[i][j]
else:
if color == '0':
out[i][j] = 0
elif color == '255':
out[i][j] = 255
else:
return 2
cv2.imwrite(result_path, out)
return 1

@ -0,0 +1,199 @@
#coding=utf8
import cv2
import numpy as np
def roberts(img_name, result_name, val1, val2, exp):
img_path = 'apps/assets/' + img_name
result_path = 'apps/results/' + result_name
try:
val1 = float(val1)
val2 = float(val2)
exp = float(exp)
except ValueError:
return 2
if (val1 < 0) or (val2 < 0):
return 2
img = cv2.imread(img_path)
gray_image = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
kernel_x = np.array([[-1, 0], [0, 1]], dtype=int)
kernel_y = np.array([[0, -1], [1, 0]], dtype=int)
cal_x = cv2.filter2D(gray_image, cv2.CV_16S, kernel_x)
cal_y = cv2.filter2D(gray_image, cv2.CV_16S, kernel_y)
abs_x = cv2.convertScaleAbs(cal_x)
abs_y = cv2.convertScaleAbs(cal_y)
roberts_res = cv2.addWeighted(abs_x, val1, abs_y, val2, exp)
cv2.imwrite(result_path, roberts_res)
return 1
def sobel(img_name, result_name, val1, val2, exp):
img_path = 'apps/assets/' + img_name
result_path = 'apps/results/' + result_name
try:
val1 = float(val1)
val2 = float(val2)
exp = float(exp)
except ValueError:
return 2
if (val1 < 0) or (val2 < 0):
return 2
img = cv2.imread(img_path)
gray_image = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
kernel_x = cv2.Sobel(gray_image, cv2.CV_16S, 1, 0)
kernel_y = cv2.Sobel(gray_image, cv2.CV_16S, 0, 1)
abs_x = cv2.convertScaleAbs(kernel_x)
abs_y = cv2.convertScaleAbs(kernel_y)
sobel_res = cv2.addWeighted(abs_x, val1, abs_y, val2, exp)
cv2.imwrite(result_path, sobel_res)
return 1
def laplacian(img_name, result_name, kernel_size, exp, k_size):
img_path = 'apps/assets/' + img_name
result_path = 'apps/results/' + result_name
try:
kernel_size = int(kernel_size)
exp = float(exp)
k_size = int(k_size)
except ValueError:
return 2
if (kernel_size <= 0) or (kernel_size % 2 == 0) or (k_size <= 0) or (k_size % 2 == 0):
return 2
img = cv2.imread(img_path)
gray_image = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
blur = cv2.GaussianBlur(gray_image, (kernel_size, kernel_size), exp)
dst = cv2.Laplacian(blur, cv2.CV_16S, ksize=k_size)
laplacian_res = cv2.convertScaleAbs(dst)
cv2.imwrite(result_path, laplacian_res)
return 1
def LoG(img_name, result_name):
img_path = 'apps/assets/' + img_name
result_path = 'apps/results/' + result_name
img = cv2.imread(img_path)
img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
image = cv2.copyMakeBorder(img, 2, 2, 2, 2, borderType=cv2.BORDER_REPLICATE)
image = cv2.GaussianBlur(image, (3, 3), 0, 0)
LoGMatr = [[0, 0, -1, 0, 0], [0, -1, -2, -1, 0], [-1, -2, 16, -2, -1], [0, -1, -2, -1, 0], [0, 0, -1, 0, 0]]
img_m1 = np.array(LoGMatr)
rows = image.shape[0]
cols = image.shape[1]
image1 = np.zeros(image.shape)
for k in range(0, 2):
for i in range(2, rows - 2):
for j in range(2, cols - 2):
image1[i, j] = np.sum((img_m1 * image[i - 2:i + 3, j - 2:j + 3, k]))
image1 = cv2.convertScaleAbs(image1)
cv2.imwrite(result_path, image1)
return 1
def canny(img_name, result_name, kernel_size, exp):
img_path = 'apps/assets/' + img_name
result_path = 'apps/results/' + result_name
try:
kernel_size = int(kernel_size)
exp = float(exp)
except ValueError:
return 2
if (kernel_size <= 0) or (kernel_size % 2 == 0):
return 2
img = cv2.imread(img_path)
blur = cv2.GaussianBlur(img, (kernel_size, kernel_size), exp)
gray_image = cv2.cvtColor(blur, cv2.COLOR_BGR2GRAY)
grad_x = cv2.Sobel(gray_image, cv2.CV_16SC1, 1, 0)
grad_y = cv2.Sobel(gray_image, cv2.CV_16SC1, 0, 1)
edge_output = cv2.Canny(grad_x, grad_y, 50, 150)
cv2.imwrite(result_path, edge_output)
return 1
def hough_lines(img_name, result_name):
img_path = 'apps/assets/' + img_name
result_path = 'apps/results/' + result_name
img = cv2.imread(img_path)
img = cv2.GaussianBlur(img, (3, 3), 0)
edges = cv2.Canny(img, 50, 150, apertureSize=3)
lines = cv2.HoughLines(edges, 1, np.pi / 2, 118)
result = img.copy()
for i_line in lines:
for line in i_line:
rho = line[0]
theta = line[1]
if (theta < (np.pi / 4.)) or (theta > (3. * np.pi / 4.0)): # 垂直直线
pt1 = (int(rho / np.cos(theta)), 0)
pt2 = (int((rho - result.shape[0] * np.sin(theta)) / np.cos(theta)), result.shape[0])
cv2.line(result, pt1, pt2, (0, 0, 255))
else:
pt1 = (0, int(rho / np.sin(theta)))
pt2 = (result.shape[1], int((rho - result.shape[1] * np.cos(theta)) / np.sin(theta)))
cv2.line(result, pt1, pt2, (0, 0, 255), 1)
cv2.imwrite(result_path, result)
return 1
def hough_lines_p(img_name, result_name):
img_path = 'apps/assets/' + img_name
result_path = 'apps/results/' + result_name
img = cv2.imread(img_path)
img = cv2.GaussianBlur(img, (3, 3), 0)
edges = cv2.Canny(img, 50, 150, apertureSize=3)
min_line_length = 200
max_line_gap = 15
lines_p = cv2.HoughLinesP(edges, 1, np.pi / 180, 80, min_line_length, max_line_gap)
result_p = img.copy()
for i_P in lines_p:
for x1, y1, x2, y2 in i_P:
cv2.line(result_p, (x1, y1), (x2, y2), (0, 255, 0), 3)
cv2.imwrite(result_path, result_p)
return 1

@ -0,0 +1,35 @@
# -*- coding: utf-8 -*-
# @File : settings.py
# @Author : AaronJny
# @Time : 2020/03/13
# @Desc :
# 内容特征层及loss加权系数
CONTENT_LAYERS = {'block4_conv2': 0.5, 'block5_conv2': 0.5}
# 风格特征层及loss加权系数
STYLE_LAYERS = {'block1_conv1': 0.2, 'block2_conv1': 0.2, 'block3_conv1': 0.2, 'block4_conv1': 0.2,
'block5_conv1': 0.2}
# 内容图片路径
CONTENT_IMAGE_PATH = './images/content_2.jpg'
# 风格图片路径
STYLE_IMAGE_PATH = './images/style_2.jpg'
# 生成图片的保存目录
OUTPUT_DIR = './output'
# 内容loss总加权系数
CONTENT_LOSS_FACTOR = 1
# 风格loss总加权系数
STYLE_LOSS_FACTOR = 100
# 图片宽度
WIDTH = 450
# 图片高度
HEIGHT = 300
# 训练epoch数
EPOCHS = 1
# 每个epoch训练多少次
STEPS_PER_EPOCH = 100
# 学习率
LEARNING_RATE = 0.03

@ -0,0 +1,222 @@
#coding=utf8
import cv2
import numpy as np
from apps.service import utils
def smoo_neighbour_average(img_name, result_name, kernel_size):
img_path = 'apps/assets/' + img_name
result_path = 'apps/results/' + result_name
try:
kernel_size = int(kernel_size)
except ValueError:
return 2
if (kernel_size <= 0) or (kernel_size % 2 == 0):
return 2
img = cv2.imread(img_path)
result = cv2.blur(img, (kernel_size, kernel_size))
cv2.imwrite(result_path, result)
return 1
def smoo_median_filter(img_name, result_name, kernel_size):
img_path = 'apps/assets/' + img_name
result_path = 'apps/results/' + result_name
try:
kernel_size = int(kernel_size)
except ValueError:
return 2
if (kernel_size <= 0) or (kernel_size % 2 == 0):
return 2
img = cv2.imread(img_path)
result = cv2.medianBlur(img, kernel_size)
cv2.imwrite(result_path, result)
return 1
def shar_robert(img_name, result_name):
img_path = 'apps/assets/' + img_name
result_path = 'apps/results/' + result_name
img = cv2.imread(img_path)
h = img.shape[0]
w = img.shape[1]
result = np.zeros(img.shape, np.uint8)
for i in range(1, h - 1):
for j in range(1, w - 1):
result[i][j] = np.abs(img[i][j].astype(int) - img[i + 1][j + 1].astype(int)) + np.abs(
img[i + 1][j].astype(int) - img[i][j + 1].astype(int))
cv2.imwrite(result_path, result)
return 1
def shar_laplacian(img_name, result_name):
img_path = 'apps/assets/' + img_name
result_path = 'apps/results/' + result_name
img = cv2.imread(img_path)
h = img.shape[0]
w = img.shape[1]
result = np.zeros(img.shape, np.uint8)
for i in range(1, h - 1):
for j in range(1, w - 1):
result[i][j] = 4 * img[i][j].astype(int) - img[i + 1][j].astype(int) - img[i - 1][j].astype(int) - \
img[i][j + 1].astype(int) - img[i][j - 1].astype(int)
cv2.imwrite(result_path, result)
return 1
def shar_sobel(img_name, result_name):
img_path = 'apps/assets/' + img_name
result_path = 'apps/results/' + result_name
img = cv2.imread(img_path)
kern_x = np.array([[-1, 0, 1], [-2, 0, 2], [-1, 0, 1]])
kern_y = np.array([[-1, -2, -1], [0, 0, 0], [1, 2, 1]])
img_x = cv2.filter2D(img, -1, kern_x, borderType=cv2.BORDER_REFLECT)
img_y = cv2.filter2D(img, -1, kern_y, borderType=cv2.BORDER_REFLECT)
abs_x = cv2.convertScaleAbs(img_x)
abs_y = cv2.convertScaleAbs(img_y)
result = cv2.addWeighted(abs_x, 0.5, abs_y, 0.5, 0)
cv2.imwrite(result_path, result)
return 1
def shar_prewitt(img_name, result_name):
img_path = 'apps/assets/' + img_name
result_path = 'apps/results/' + result_name
img = cv2.imread(img_path)
kern_x = np.array([[1, 1, 1], [0, 0, 0], [-1, -1, -1]])
kern_y = np.array([[-1, 0, 1], [-1, 0, 1], [-1, 0, 1]])
img_x = cv2.filter2D(img, cv2.CV_16S, kern_x)
img_y = cv2.filter2D(img, cv2.CV_16S, kern_y)
abs_x = cv2.convertScaleAbs(img_x)
abs_y = cv2.convertScaleAbs(img_y)
result = cv2.addWeighted(abs_x, 0.5, abs_y, 0.5, 0)
cv2.imwrite(result_path, result)
return 1
def smoo_ideal_filter(img_name, result_name, d0):
img_path = 'apps/assets/' + img_name
result_path = 'apps/results/' + result_name
try:
d0 = int(d0)
except ValueError:
return 2
if (d0 < 0) or (d0 > 255):
return 2
img = cv2.imread(img_path, 0)
ideal_filter = utils.ideal_low_filter(img, d0)
result = utils.filter_use(img, ideal_filter)
cv2.imwrite(result_path, result)
return 1
def smoo_barte_filter(img_name, result_name, d0, rank):
img_path = 'apps/assets/' + img_name
result_path = 'apps/results/' + result_name
try:
d0 = int(d0)
rank = int(rank)
except ValueError:
return 2
if (d0 < 0) or (d0 > 255):
return 2
img = cv2.imread(img_path, 0)
butterworth_filter = utils.butterworth_low_filter(img, d0, rank)
result = utils.filter_use(img, butterworth_filter)
cv2.imwrite(result_path, result)
return 1
def smoo_exp_filter(img_name, result_name, d0, rank):
img_path = 'apps/assets/' + img_name
result_path = 'apps/results/' + result_name
try:
d0 = int(d0)
rank = int(rank)
except ValueError:
return 2
if (d0 < 0) or (d0 > 255):
return 2
img = cv2.imread(img_path, 0)
exp_filter = utils.exp_low_filter(img, d0, rank)
result = utils.filter_use(img, exp_filter)
cv2.imwrite(result_path, result)
return 1
def shar_ideal_high(img_name, result_name, d0):
img_path = 'apps/assets/' + img_name
result_path = 'apps/results/' + result_name
try:
d0 = int(d0)
except ValueError:
return 2
if (d0 < 0) or (d0 > 255):
return 2
img = cv2.imread(img_path, 0)
ideal_filter = utils.ideal_high_filter(img, d0)
result = utils.filter_use2(img, ideal_filter)
cv2.imwrite(result_path, result)
return 1
def shar_barte_filter(img_name, result_name, d0, rank):
img_path = 'apps/assets/' + img_name
result_path = 'apps/results/' + result_name
try:
d0 = int(d0)
rank = int(rank)
except ValueError:
return 2
if (d0 < 0) or (d0 > 255):
return 2
img = cv2.imread(img_path, 0)
butterworth_filter = utils.butterworth_high_filter(img, d0, rank)
result = utils.filter_use2(img, butterworth_filter)
cv2.imwrite(result_path, result)
return 1
def shar_exp_filter(img_name, result_name, d0, rank):
img_path = 'apps/assets/' + img_name
result_path = 'apps/results/' + result_name
try:
d0 = int(d0)
rank = int(rank)
except ValueError:
return 2
if (d0 < 0) or (d0 > 255):
return 2
img = cv2.imread(img_path, 0)
exp_filter = utils.exp_high_filter(img, d0, rank)
result = utils.filter_use2(img, exp_filter)
cv2.imwrite(result_path, result)
return 1

@ -0,0 +1,143 @@
import os
import numpy as np
from tqdm import tqdm
import tensorflow as tf
from apps.service.model import NeuralStyleTransferModel
from apps.service import settings
from apps.service import utils
def _compute_content_loss(noise_features, target_features):
"""
计算指定层上两个特征之间的内容loss
:param noise_features: 噪声图片在指定层的特征
:param target_features: 内容图片在指定层的特征
"""
content_loss = tf.reduce_sum(tf.square(noise_features - target_features))
# 计算系数
x = 2. * M * N
content_loss = content_loss / x
return content_loss
def compute_content_loss(noise_content_features, target_content_features):
"""
计算并当前图片的内容loss
:param noise_content_features: 噪声图片的内容特征
"""
# 初始化内容损失
content_losses = []
# 加权计算内容损失
for (noise_feature, factor), (target_feature, _) in zip(noise_content_features, target_content_features):
layer_content_loss = _compute_content_loss(noise_feature, target_feature)
content_losses.append(layer_content_loss * factor)
return tf.reduce_sum(content_losses)
def gram_matrix(feature):
"""
计算给定特征的格拉姆矩阵
"""
# 先交换维度把channel维度提到最前面
x = tf.transpose(feature, perm=[2, 0, 1])
# reshape压缩成2d
x = tf.reshape(x, (x.shape[0], -1))
# 计算x和x的逆的乘积
return x @ tf.transpose(x)
def _compute_style_loss(noise_feature, target_feature):
"""
计算指定层上两个特征之间的风格loss
:param noise_feature: 噪声图片在指定层的特征
:param target_feature: 风格图片在指定层的特征
"""
noise_gram_matrix = gram_matrix(noise_feature)
style_gram_matrix = gram_matrix(target_feature)
style_loss = tf.reduce_sum(tf.square(noise_gram_matrix - style_gram_matrix))
# 计算系数
x = 4. * (M ** 2) * (N ** 2)
return style_loss / x
def compute_style_loss(noise_style_features, target_style_features):
"""
计算并返回图片的风格loss
:param noise_style_features: 噪声图片的风格特征
"""
style_losses = []
for (noise_feature, factor), (target_feature, _) in zip(noise_style_features, target_style_features):
layer_style_loss = _compute_style_loss(noise_feature, target_feature)
style_losses.append(layer_style_loss * factor)
return tf.reduce_sum(style_losses)
def total_loss(noise_features, target_content_features, target_style_features):
"""
计算总损失
:param noise_features: 噪声图片特征数据
"""
content_loss = compute_content_loss(noise_features['content'], target_content_features)
style_loss = compute_style_loss(noise_features['style'], target_style_features)
return content_loss * settings.CONTENT_LOSS_FACTOR + style_loss * settings.STYLE_LOSS_FACTOR
# 创建模型
model = NeuralStyleTransferModel()
M = settings.WIDTH * settings.HEIGHT
N = 3
# 使用tf.function加速训练
@tf.function
def train_one_step(optimizer, noise_image, target_content_features, target_style_features):
"""
一次迭代过程
"""
# 求loss
with tf.GradientTape() as tape:
noise_outputs = model(noise_image)
loss = total_loss(noise_outputs, target_content_features, target_style_features)
# 求梯度
grad = tape.gradient(loss, noise_image)
# 梯度下降,更新噪声图片
optimizer.apply_gradients([(grad, noise_image)])
return loss
def style_transfer(img_style_path, img_content_path, result_path, epoch, per_epoch, learn_rate):
learn_rate = learn_rate or settings.LEARNING_RATE
# 使用Adma优化器
optimizer = tf.keras.optimizers.Adam(learning_rate=learn_rate)
# 加载内容图片
content_image = utils.load_images(img_content_path)
# 风格图片
style_image = utils.load_images(img_style_path)
# 计算出目标内容图片的内容特征备用
target_content_features = model([content_image, ])['content']
# 计算目标风格图片的风格特征
target_style_features = model([style_image, ])['style']
# 基于内容图片随机生成一张噪声图片
noise_image = tf.Variable((content_image + np.random.uniform(-0.2, 0.2, (1, settings.HEIGHT, settings.WIDTH, 3))) / 2)
epoch = epoch or settings.EPOCHS
per_epoch = per_epoch or settings.STEPS_PER_EPOCH
# 共训练epoch个epochs
for epo in range(epoch):
# 使用tqdm提示训练进度
with tqdm(total=per_epoch, desc='Epoch {}/{}'.format(epo + 1, epoch)) as pbar:
# 每个epoch训练per_epoch次
for step in range(per_epoch):
_loss = train_one_step(optimizer, noise_image, target_content_features, target_style_features)
pbar.set_postfix({'loss': '%.4f' % float(_loss)})
pbar.update(1)
# 每个epoch保存一次图片
print(222)
utils.save_image(noise_image, result_path)

@ -0,0 +1,14 @@
from apps.service import style
def style_transfer(img_style_name, img_content_name, result_name, epoch, per_epoch, learn_rate):
img_style_path = 'apps/assets/' + img_style_name
img_content_path = 'apps/assets/' + img_content_name
result_path = 'apps/results/' + result_name
try:
style.style_transfer(img_style_path, img_content_path, result_path, int(epoch), int(per_epoch), float(learn_rate))
except Exception as e:
print(e)
return 2
return 1

@ -0,0 +1,300 @@
#coding=utf8
import matplotlib.pyplot as plt
import cv2
import numpy as np
from math import *
from flask import jsonify
import tensorflow as tf
from apps.service import settings
def wrap_success_json(result_name):
result_name = 'http://127.0.0.1:5000/api/get_res_file/' + result_name
return_data = {'code': '1', 'message': 'Success', 'result_name': result_name}
return jsonify(return_data)
def wrap_failure_json(result_name):
result_name = 'http://127.0.0.1:5000/api/get_res_file/' + result_name
return_data = {'code': '2', 'message': 'Failure', 'result_name': result_name}
return jsonify(return_data)
def img_expand(img1, img2):
shape1 = img1.shape
shape2 = img2.shape
row1 = shape1[0]
col1 = shape1[1]
row2 = shape2[0]
col2 = shape2[1]
if row1 > row2:
row = row1
else:
row = row2
if col1 > col2:
col = col1
else:
col = col2
if (row - row1) % 2 != 0:
r11 = int((row - row1) / 2)
r12 = r11 + 1
else:
r11 = r12 = int((row - row1) / 2)
if (col - col1) % 2 != 0:
c11 = int((col - col1) / 2)
c12 = c11 + 1
else:
c11 = c12 = int((col - col1) / 2)
if (row - row2) % 2 != 0:
r21 = int((row - row2) / 2)
r22 = r21 + 1
else:
r21 = r22 = int((row - row2) / 2)
if (col - col2) % 2 != 0:
c21 = int((col - col2) / 2)
c22 = c21 + 1
else:
c21 = c22 = int((col - col2) / 2)
img1 = cv2.copyMakeBorder(img1, r11, r12, c11, c12, cv2.BORDER_CONSTANT, value=[255, 255, 255])
img2 = cv2.copyMakeBorder(img2, r21, r22, c21, c22, cv2.BORDER_CONSTANT, value=[255, 255, 255])
return img1, img2
def swap(val1, val2):
return val2, val1
def order_desc(array):
# 列表的长度
length = len(array)
# 对列表进行选择排序,获得有序的列表
for i in range(length):
for j in range(i + 1, length):
# 选择最大的值
if array[j] > array[i]:
# 交换位置
temp = array[j]
array[j] = array[i]
array[i] = temp
return array
def grayHist(img, filename):
plt.figure(filename, figsize=(16, 8))
plt.subplot(121)
plt.imshow(img, 'gray')
plt.subplot(122)
h, w = img.shape[:2]
pixelSequence = img.reshape(1, h * w)
numberBins = 256
histogram, bins, patch = plt.hist(img.ravel(), 256, [0, 255])
plt.xlabel("gray label")
plt.ylabel("number of pixels")
plt.axis([0, 255, 0, np.max(histogram)])
plt.savefig(filename)
plt.show()
def rotate(image, angle):
height, width, channels = image.shape
heightNew = int(width * fabs(sin(radians(angle))) + height * fabs(cos(radians(angle))))
widthNew = int(height * fabs(sin(radians(angle))) + width * fabs(cos(radians(angle))))
matRotation = cv2.getRotationMatrix2D((width / 2, height / 2), angle, 1)
matRotation[0, 2] += (widthNew - width) / 2
matRotation[1, 2] += (heightNew - height) / 2
imgRotation = None
if channels == 1:
imgRotation = cv2.warpAffine(image, matRotation, (widthNew, heightNew), borderValue=(255))
elif channels == 3:
imgRotation = cv2.warpAffine(image, matRotation, (widthNew, heightNew), borderValue=(255, 255, 255))
return imgRotation
# 频域平滑
def ideal_low_filter(img, D0):
"""
生成一个理想低通滤波器并返回
"""
h, w = img.shape[:2]
filter_img = np.ones((h, w))
u = np.fix(h / 2)
v = np.fix(w / 2)
for i in range(h):
for j in range(w):
d = np.sqrt((i - u) ** 2 + (j - v) ** 2)
filter_img[i, j] = 0 if d > D0 else 1
return filter_img
def butterworth_low_filter(img, D0, rank):
"""
生成一个Butterworth低通滤波器并返回
"""
h, w = img.shape[:2]
filter_img = np.zeros((h, w))
u = np.fix(h / 2)
v = np.fix(w / 2)
for i in range(h):
for j in range(w):
d = np.sqrt((i - u) ** 2 + (j - v) ** 2)
filter_img[i, j] = 1 / (1 + 0.414 * (d / D0) ** (2 * rank))
return filter_img
def exp_low_filter(img, D0, rank):
"""
生成一个指数低通滤波器并返回
"""
h, w = img.shape[:2]
filter_img = np.zeros((h, w))
u = np.fix(h / 2)
v = np.fix(w / 2)
for i in range(h):
for j in range(w):
d = np.sqrt((i - u) ** 2 + (j - v) ** 2)
filter_img[i, j] = np.exp(np.log(1 / np.sqrt(2)) * (d / D0) ** (2 * rank))
return filter_img
def filter_use(img, filter):
"""
将图像img与滤波器filter结合生成对应的滤波图像
"""
# 首先进行傅里叶变换
f = np.fft.fft2(img)
f_center = np.fft.fftshift(f)
# 应用滤波器进行反变换
S = np.multiply(f_center, filter) # 频率相乘——l(u,v)*H(u,v)
f_origin = np.fft.ifftshift(S) # 将低频移动到原来的位置
f_origin = np.fft.ifft2(f_origin) # 使用ifft2进行傅里叶的逆变换
f_origin = np.abs(f_origin) # 设置区间
return f_origin
def DFT_show(img):
"""
对传入的图像进行傅里叶变换生成频域图像
"""
f = np.fft.fft2(img) # 使用numpy进行傅里叶变换
fshift = np.fft.fftshift(f) # 把零频率分量移到中间
result = np.log(1 + abs(fshift))
return result
# 频域锐化
def ideal_high_filter(img, D0):
"""
生成一个理想高通滤波器并返回
"""
h, w = img.shape[:2]
filter_img = np.zeros((h, w))
u = np.fix(h / 2)
v = np.fix(w / 2)
for i in range(h):
for j in range(w):
d = np.sqrt((i - u) ** 2 + (j - v) ** 2)
filter_img[i, j] = 0 if d < D0 else 1
return filter_img
def butterworth_high_filter(img, D0, rank):
"""
生成一个Butterworth高通滤波器并返回
"""
h, w = img.shape[:2]
filter_img = np.zeros((h, w))
u = np.fix(h / 2)
v = np.fix(w / 2)
for i in range(h):
for j in range(w):
d = np.sqrt((i - u) ** 2 + (j - v) ** 2)
filter_img[i, j] = 1 / (1 + (D0 / d) ** (2 * rank))
return filter_img
def exp_high_filter(img, D0, rank):
"""
生成一个指数高通滤波器并返回
"""
h, w = img.shape[:2]
filter_img = np.zeros((h, w))
u = np.fix(h / 2)
v = np.fix(w / 2)
for i in range(h):
for j in range(w):
d = np.sqrt((i - u) ** 2 + (j - v) ** 2)
filter_img[i, j] = np.exp((-1) * (D0 / d) ** rank)
return filter_img
def filter_use2(img, filter):
"""
将图像img与滤波器filter结合生成对应的滤波图像
"""
# 首先进行傅里叶变换
f = np.fft.fft2(img)
f_center = np.fft.fftshift(f)
# 应用滤波器进行反变换
S = np.multiply(f_center, filter) # 频率相乘——l(u,v)*H(u,v)
f_origin = np.fft.ifftshift(S) # 将低频移动到原来的位置
f_origin = np.fft.ifft2(f_origin) # 使用ifft2进行傅里叶的逆变换
f_origin = np.abs(f_origin) # 设置区间
f_origin = f_origin / np.max(f_origin.all())
return f_origin
# 我们准备使用经典网络在imagenet数据集上的与训练权重所以归一化时也要使用imagenet的平均值和标准差
image_mean = tf.constant([0.485, 0.456, 0.406])
image_std = tf.constant([0.299, 0.224, 0.225])
def normalization(x):
"""
对输入图片x进行归一化返回归一化的值
"""
return (x - image_mean) / image_std
def load_images(image_path, width=settings.WIDTH, height=settings.HEIGHT):
"""
加载并处理图片
:param image_path: 图片路径
:param width: 图片宽度
:param height: 图片长度
:return: 一个张量
"""
# 加载文件
x = tf.io.read_file(image_path)
# 解码图片
x = tf.image.decode_jpeg(x, channels=3)
# 修改图片大小
x = tf.image.resize(x, [height, width])
x = x / 255.
# 归一化
x = normalization(x)
x = tf.reshape(x, [1, height, width, 3])
# 返回结果
return x
def save_image(image, filename):
x = tf.reshape(image, image.shape[1:])
x = x * image_std + image_mean
x = x * 255.
x = tf.cast(x, tf.int32)
x = tf.clip_by_value(x, 0, 255)
x = tf.cast(x, tf.uint8)
x = tf.image.encode_jpeg(x)
tf.io.write_file(filename, x)

@ -0,0 +1,163 @@
from flask import Blueprint, request
from apps.service import basicFuncService, utils
app = Blueprint('basicFuncViews', __name__)
@app.route('/api/basic_func/graying')
def graying():
request_values = request.args
request_values.to_dict()
code = basicFuncService.graying(request_values['img_name'], request_values['result_name'])
if code == 2:
return utils.wrap_failure_json(request_values['result_name'])
return utils.wrap_success_json(request_values['result_name'])
@app.route('/api/basic_func/thresholding')
def thresholding():
request_values = request.args
request_values.to_dict()
code = basicFuncService.thresholding(request_values['img_name'], request_values['result_name'])
if code == 2:
return utils.wrap_failure_json(request_values['result_name'])
return utils.wrap_success_json(request_values['result_name'])
@app.route('/api/basic_func/logical_and')
def logical_and():
request_values = request.args
request_values.to_dict()
code = basicFuncService.logical_and(request_values['img_name1'], request_values['img_name2'], request_values['result_name'])
if code == 2:
return utils.wrap_failure_json(request_values['result_name'])
return utils.wrap_success_json(request_values['result_name'])
@app.route('/api/basic_func/logical_or')
def logical_or():
request_values = request.args
request_values.to_dict()
code = basicFuncService.logical_or(request_values['img_name1'], request_values['img_name2'], request_values['result_name'])
if code == 2:
return utils.wrap_failure_json(request_values['result_name'])
return utils.wrap_success_json(request_values['result_name'])
@app.route('/api/basic_func/logical_not')
def logical_not():
request_values = request.args
request_values.to_dict()
code = basicFuncService.logical_not(request_values['img_name'], request_values['result_name'])
if code == 2:
return utils.wrap_failure_json(request_values['result_name'])
return utils.wrap_success_json(request_values['result_name'])
@app.route('/api/basic_func/add')
def add():
request_values = request.args
request_values.to_dict()
code = basicFuncService.add(request_values['img_name1'], request_values['img_name2'], request_values['result_name'])
if code == 2:
return utils.wrap_failure_json(request_values['result_name'])
return utils.wrap_success_json(request_values['result_name'])
@app.route('/api/basic_func/subtract')
def subtract():
request_values = request.args
request_values.to_dict()
code = basicFuncService.subtract(request_values['img_name1'], request_values['img_name2'], request_values['result_name'])
if code == 2:
return utils.wrap_failure_json(request_values['result_name'])
return utils.wrap_success_json(request_values['result_name'])
@app.route('/api/basic_func/multiply')
def multiply():
request_values = request.args
request_values.to_dict()
code = basicFuncService.multiply(request_values['img_name1'], request_values['img_name2'], request_values['result_name'])
if code == 2:
return utils.wrap_failure_json(request_values['result_name'])
return utils.wrap_success_json(request_values['result_name'])
@app.route('/api/basic_func/divide')
def divide():
request_values = request.args
request_values.to_dict()
code = basicFuncService.divide(request_values['img_name1'], request_values['img_name2'], request_values['result_name'])
if code == 2:
return utils.wrap_failure_json(request_values['result_name'])
return utils.wrap_success_json(request_values['result_name'])
@app.route('/api/basic_func/flip')
def flip():
request_values = request.args
request_values.to_dict()
code = basicFuncService.flip(request_values['img_name'], request_values['result_name'], request_values['fli_choi'])
if code == 2:
return utils.wrap_failure_json(request_values['result_name'])
return utils.wrap_success_json(request_values['result_name'])
@app.route('/api/basic_func/move')
def move():
request_values = request.args
request_values.to_dict()
code = basicFuncService.move(request_values['img_name'], request_values['result_name'], request_values['move_x']
, request_values['move_y'])
if code == 2:
return utils.wrap_failure_json(request_values['result_name'])
return utils.wrap_success_json(request_values['result_name'])
@app.route('/api/basic_func/rotate')
def rotate():
request_values = request.args
request_values.to_dict()
code = basicFuncService.rotate(request_values['img_name'], request_values['result_name'], request_values['angle'])
if code == 2:
return utils.wrap_failure_json(request_values['result_name'])
return utils.wrap_success_json(request_values['result_name'])
@app.route('/api/basic_func/resize')
def resize():
request_values = request.args
request_values.to_dict()
code = basicFuncService.resize(request_values['img_name'], request_values['result_name'], request_values['size_x']
, request_values['size_y'])
if code == 2:
return utils.wrap_failure_json(request_values['result_name'])
return utils.wrap_success_json(request_values['result_name'])

@ -0,0 +1,38 @@
#coding=utf8
import os
from flask import Blueprint, jsonify, request, send_file
from apps.service.filesService import resp_file_upload, resp_file_download
app = Blueprint('filesView', __name__)
@app.route('/api/file/upload', methods=['POST'])
def file_upload():
file = request.files['file']
resp_data = resp_file_upload(file)
return jsonify(resp_data)
@app.route('/api/file/download', methods=['POST'])
def file_download():
requ_data = request.json
return resp_file_download(requ_data)
@app.route('/api/get_ori_file/<file_name>', methods=['GET'])
def get_ori_file(file_name):
file_path = os.path.join('assets/', file_name)
# 向api返回图片文件
return send_file(file_path)
@app.route('/api/get_res_file/<file_name>', methods=['GET'])
def get_res_file(file_name):
file_path = os.path.join('results/', file_name)
# 向api返回图片文件
return send_file(file_path)

@ -0,0 +1,28 @@
from flask import Blueprint, request
from apps.service import histogramService, utils
app = Blueprint('histogramViews', __name__)
@app.route('/api/histogram/gray')
def gray_histogram():
request_values = request.args
request_values.to_dict()
code = histogramService.gray_histogram(request_values['img_name'], request_values['result_name'])
if code == 2:
return utils.wrap_failure_json(request_values['result_name'])
return utils.wrap_success_json(request_values['result_name'])
@app.route('/api/histogram/bgr')
def bgr_histogram():
request_values = request.args
request_values.to_dict()
code = histogramService.bgr_histogram(request_values['img_name'], request_values['result_name'])
if code == 2:
return utils.wrap_failure_json(request_values['result_name'])
return utils.wrap_success_json(request_values['result_name'])

@ -0,0 +1,53 @@
from flask import Blueprint, request
from apps.service import morphologicalService, utils
app = Blueprint('morphologicalViews', __name__)
@app.route('/api/morphological/erode')
def erode():
request_values = request.args
request_values.to_dict()
code = morphologicalService.erode(request_values['img_name'], request_values['result_name'], request_values['kernel_type'], request_values['kernel_size'])
if code == 2:
return utils.wrap_failure_json(request_values['result_name'])
return utils.wrap_success_json(request_values['result_name'])
@app.route('/api/morphological/dilate')
def dilate():
request_values = request.args
request_values.to_dict()
code = morphologicalService.dilate(request_values['img_name'], request_values['result_name'], request_values['kernel_type'], request_values['kernel_size'])
if code == 2:
return utils.wrap_failure_json(request_values['result_name'])
return utils.wrap_success_json(request_values['result_name'])
@app.route('/api/morphological/mor_open')
def mor_open():
request_values = request.args
request_values.to_dict()
code = morphologicalService.mor_open(request_values['img_name'], request_values['result_name'], request_values['kernel_type'], request_values['kernel_size'])
if code == 2:
return utils.wrap_failure_json(request_values['result_name'])
return utils.wrap_success_json(request_values['result_name'])
@app.route('/api/morphological/mor_close')
def mor_close():
request_values = request.args
request_values.to_dict()
code = morphologicalService.mor_close(request_values['img_name'], request_values['result_name'], request_values['kernel_type'], request_values['kernel_size'])
if code == 2:
return utils.wrap_failure_json(request_values['result_name'])
return utils.wrap_success_json(request_values['result_name'])

@ -0,0 +1,113 @@
from flask import Blueprint, request
from apps.service import repairService, utils
app = Blueprint('repairViews', __name__)
@app.route('/api/repair/gauss_noise')
def gauss_noise():
request_values = request.args
request_values.to_dict()
code = repairService.gauss_noise(request_values['img_name'], request_values['result_name'])
if code == 2:
return utils.wrap_failure_json(request_values['result_name'])
return utils.wrap_success_json(request_values['result_name'])
@app.route('/api/repair/sault_pepper_noise')
def sault_pepper_noise():
request_values = request.args
request_values.to_dict()
code = repairService.sault_pepper_noise(request_values['img_name'], request_values['result_name'], request_values['ran_x1'], request_values['ran_y1'], request_values['ran_x2'], request_values['ran_y2'])
if code == 2:
return utils.wrap_failure_json(request_values['result_name'])
return utils.wrap_success_json(request_values['result_name'])
@app.route('/api/repair/arithmetic_average_filter')
def arithmetic_average_filter():
request_values = request.args
request_values.to_dict()
code = repairService.arithmetic_average_filter(request_values['img_name'], request_values['result_name'], request_values['filter_size_p'], request_values['filter_size_q'])
if code == 2:
return utils.wrap_failure_json(request_values['result_name'])
return utils.wrap_success_json(request_values['result_name'])
@app.route('/api/repair/geometric_average_filter')
def geometric_average_filter():
request_values = request.args
request_values.to_dict()
code = repairService.geometric_average_filter(request_values['img_name'], request_values['result_name'], request_values['filter_size_p'], request_values['filter_size_q'])
if code == 2:
return utils.wrap_failure_json(request_values['result_name'])
return utils.wrap_success_json(request_values['result_name'])
@app.route('/api/repair/harmonic_average_filter')
def harmonic_average_filter():
request_values = request.args
request_values.to_dict()
code = repairService.harmonic_average_filter(request_values['img_name'], request_values['result_name'], request_values['filter_size_p'], request_values['filter_size_q'])
if code == 2:
return utils.wrap_failure_json(request_values['result_name'])
return utils.wrap_success_json(request_values['result_name'])
@app.route('/api/repair/min_filter')
def min_filter():
request_values = request.args
request_values.to_dict()
code = repairService.min_filter(request_values['img_name'], request_values['result_name'])
if code == 2:
return utils.wrap_failure_json(request_values['result_name'])
return utils.wrap_success_json(request_values['result_name'])
@app.route('/api/repair/max_filter')
def max_filter():
request_values = request.args
request_values.to_dict()
code = repairService.max_filter(request_values['img_name'], request_values['result_name'])
if code == 2:
return utils.wrap_failure_json(request_values['result_name'])
return utils.wrap_success_json(request_values['result_name'])
@app.route('/api/repair/median_filter')
def median_filter():
request_values = request.args
request_values.to_dict()
code = repairService.median_filter(request_values['img_name'], request_values['result_name'])
if code == 2:
return utils.wrap_failure_json(request_values['result_name'])
return utils.wrap_success_json(request_values['result_name'])
@app.route('/api/repair/range_filter')
def range_filter():
request_values = request.args
request_values.to_dict()
code = repairService.range_filter(request_values['img_name'], request_values['result_name'], request_values['min'], request_values['max'], request_values['color'])
if code == 2:
return utils.wrap_failure_json(request_values['result_name'])
return utils.wrap_success_json(request_values['result_name'])

@ -0,0 +1,89 @@
from flask import Blueprint, request
from apps.service import segmentationService, utils
app = Blueprint('segmentationViews', __name__)
@app.route('/api/segmentation/roberts')
def roberts():
request_values = request.args
request_values.to_dict()
code = segmentationService.roberts(request_values['img_name'], request_values['result_name'], request_values['val1'], request_values['val2'], request_values['exp'])
if code == 2:
return utils.wrap_failure_json(request_values['result_name'])
return utils.wrap_success_json(request_values['result_name'])
@app.route('/api/segmentation/sobel')
def sobel():
request_values = request.args
request_values.to_dict()
code = segmentationService.sobel(request_values['img_name'], request_values['result_name'], request_values['val1'], request_values['val2'], request_values['exp'])
if code == 2:
return utils.wrap_failure_json(request_values['result_name'])
return utils.wrap_success_json(request_values['result_name'])
@app.route('/api/segmentation/laplacian')
def laplacian():
request_values = request.args
request_values.to_dict()
code = segmentationService.laplacian(request_values['img_name'], request_values['result_name'], request_values['kernel_size'], request_values['exp'], request_values['k_size'])
if code == 2:
return utils.wrap_failure_json(request_values['result_name'])
return utils.wrap_success_json(request_values['result_name'])
@app.route('/api/segmentation/LoG')
def LoG():
request_values = request.args
request_values.to_dict()
code = segmentationService.LoG(request_values['img_name'], request_values['result_name'])
if code == 2:
return utils.wrap_failure_json(request_values['result_name'])
return utils.wrap_success_json(request_values['result_name'])
@app.route('/api/segmentation/canny')
def canny():
request_values = request.args
request_values.to_dict()
code = segmentationService.canny(request_values['img_name'], request_values['result_name'], request_values['kernel_size'], request_values['exp'])
if code == 2:
return utils.wrap_failure_json(request_values['result_name'])
return utils.wrap_success_json(request_values['result_name'])
@app.route('/api/segmentation/hough_lines')
def hough_lines():
request_values = request.args
request_values.to_dict()
code = segmentationService.hough_lines(request_values['img_name'], request_values['result_name'])
if code == 2:
return utils.wrap_failure_json(request_values['result_name'])
return utils.wrap_success_json(request_values['result_name'])
@app.route('/api/segmentation/hough_lines_p')
def hough_lines_p():
request_values = request.args
request_values.to_dict()
code = segmentationService.hough_lines_p(request_values['img_name'], request_values['result_name'])
if code == 2:
return utils.wrap_failure_json(request_values['result_name'])
return utils.wrap_success_json(request_values['result_name'])

@ -0,0 +1,153 @@
from flask import Blueprint, request
from apps.service import smoothSharpenService, utils
app = Blueprint('smoothSharpenViews', __name__)
@app.route('/api/smooth_sharpen/smoo_neighbour_average')
def smoo_neighbour_average():
request_values = request.args
request_values.to_dict()
code = smoothSharpenService.smoo_neighbour_average(request_values['img_name'], request_values['result_name'],
request_values['kernel_size'])
if code == 2:
return utils.wrap_failure_json(request_values['result_name'])
return utils.wrap_success_json(request_values['result_name'])
@app.route('/api/smooth_sharpen/smoo_median_filter')
def smoo_median_filter():
request_values = request.args
request_values.to_dict()
code = smoothSharpenService.smoo_median_filter(request_values['img_name'], request_values['result_name'],
request_values['kernel_size'])
if code == 2:
return utils.wrap_failure_json(request_values['result_name'])
return utils.wrap_success_json(request_values['result_name'])
@app.route('/api/smooth_sharpen/shar_robert')
def shar_robert():
request_values = request.args
request_values.to_dict()
code = smoothSharpenService.shar_robert(request_values['img_name'], request_values['result_name'])
if code == 2:
return utils.wrap_failure_json(request_values['result_name'])
return utils.wrap_success_json(request_values['result_name'])
@app.route('/api/smooth_sharpen/shar_laplacian')
def shar_laplacian():
request_values = request.args
request_values.to_dict()
code = smoothSharpenService.shar_laplacian(request_values['img_name'], request_values['result_name'])
if code == 2:
return utils.wrap_failure_json(request_values['result_name'])
return utils.wrap_success_json(request_values['result_name'])
@app.route('/api/smooth_sharpen/shar_sobel')
def shar_sobel():
request_values = request.args
request_values.to_dict()
code = smoothSharpenService.shar_sobel(request_values['img_name'], request_values['result_name'])
if code == 2:
return utils.wrap_failure_json(request_values['result_name'])
return utils.wrap_success_json(request_values['result_name'])
@app.route('/api/smooth_sharpen/shar_prewitt')
def shar_prewitt():
request_values = request.args
request_values.to_dict()
code = smoothSharpenService.shar_prewitt(request_values['img_name'], request_values['result_name'])
if code == 2:
return utils.wrap_failure_json(request_values['result_name'])
return utils.wrap_success_json(request_values['result_name'])
@app.route('/api/smooth_sharpen/smoo_ideal_filter')
def smoo_ideal_filter():
request_values = request.args
request_values.to_dict()
code = smoothSharpenService.smoo_ideal_filter(request_values['img_name'], request_values['result_name'], request_values['d0'])
if code == 2:
return utils.wrap_failure_json(request_values['result_name'])
return utils.wrap_success_json(request_values['result_name'])
@app.route('/api/smooth_sharpen/smoo_barte_filter')
def smoo_barte_filter():
request_values = request.args
request_values.to_dict()
code = smoothSharpenService.smoo_barte_filter(request_values['img_name'], request_values['result_name'], request_values['d0'], request_values['rank'])
if code == 2:
return utils.wrap_failure_json(request_values['result_name'])
return utils.wrap_success_json(request_values['result_name'])
@app.route('/api/smooth_sharpen/smoo_exp_filter')
def smoo_exp_filter():
request_values = request.args
request_values.to_dict()
code = smoothSharpenService.smoo_exp_filter(request_values['img_name'], request_values['result_name'], request_values['d0'], request_values['rank'])
if code == 2:
return utils.wrap_failure_json(request_values['result_name'])
return utils.wrap_success_json(request_values['result_name'])
@app.route('/api/smooth_sharpen/shar_ideal_high')
def shar_ideal_high():
request_values = request.args
request_values.to_dict()
code = smoothSharpenService.shar_ideal_high(request_values['img_name'], request_values['result_name'], request_values['d0'])
if code == 2:
return utils.wrap_failure_json(request_values['result_name'])
return utils.wrap_success_json(request_values['result_name'])
@app.route('/api/smooth_sharpen/shar_barte_filter')
def shar_barte_filter():
request_values = request.args
request_values.to_dict()
code = smoothSharpenService.shar_barte_filter(request_values['img_name'], request_values['result_name'], request_values['d0'], request_values['rank'])
if code == 2:
return utils.wrap_failure_json(request_values['result_name'])
return utils.wrap_success_json(request_values['result_name'])
@app.route('/api/smooth_sharpen/shar_exp_filter')
def shar_exp_filter():
request_values = request.args
request_values.to_dict()
code = smoothSharpenService.shar_exp_filter(request_values['img_name'], request_values['result_name'], request_values['d0'], request_values['rank'])
if code == 2:
return utils.wrap_failure_json(request_values['result_name'])
return utils.wrap_success_json(request_values['result_name'])

@ -0,0 +1,22 @@
from flask import Blueprint, request
from apps.service import styleTransferService, utils
app = Blueprint('styleTransferViews', __name__)
@app.route('/api/styleTransfer/style_transfer')
def style_transfer():
request_values = request.args
request_values.to_dict(),
code = styleTransferService.style_transfer(request_values['img_style_name'],
request_values['img_content_name'],
request_values['result_name'],
request_values['epoch'],
request_values['per_epoch'],
request_values['learn_rate'])
if code == 2:
return utils.wrap_failure_json(request_values['result_name'])
return utils.wrap_success_json(request_values['result_name'])

@ -0,0 +1,15 @@
from flask import Blueprint, request, jsonify
app = Blueprint('testview', __name__)
@app.route('/api/test')
def hello_world(): # put application's code here
return 'Hello World!'
@app.route('/api/testinput')
def hello_test(): # put application's code here
requestValues = request.args
requestValues.to_dict()
return jsonify(requestValues)

BIN
static/.DS_Store vendored

Binary file not shown.

@ -0,0 +1,5 @@
module.exports = {
presets: [
'@vue/cli-plugin-babel/preset'
]
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 114 KiB

12520
static/package-lock.json generated

File diff suppressed because it is too large Load Diff

@ -0,0 +1,45 @@
{
"name": "static",
"version": "1.0.0",
"private": true,
"scripts": {
"serve": "vue-cli-service serve",
"build": "vue-cli-service build",
"lint": "vue-cli-service lint"
},
"dependencies": {
"axios": "^0.27.2",
"core-js": "^3.6.5",
"element-ui": "^2.15.9",
"vue": "^2.6.11",
"vue-router": "^3.5.4"
},
"devDependencies": {
"@vue/cli-plugin-babel": "~4.5.17",
"@vue/cli-plugin-eslint": "~4.5.17",
"@vue/cli-service": "~4.5.17",
"babel-eslint": "^10.1.0",
"eslint": "^6.7.2",
"eslint-plugin-vue": "^6.2.2",
"vue-template-compiler": "^2.6.11"
},
"eslintConfig": {
"root": true,
"env": {
"node": true
},
"extends": [
"plugin:vue/essential",
"eslint:recommended"
],
"parserOptions": {
"parser": "babel-eslint"
},
"rules": {}
},
"browserslist": [
"> 1%",
"last 2 versions",
"not dead"
]
}

@ -0,0 +1,17 @@
<!DOCTYPE html>
<html lang="">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width,initial-scale=1.0">
<link rel="icon" href="<%= BASE_URL %>kaori.ico">
<title>Image Processing System</title>
</head>
<body>
<noscript>
<strong>We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
</noscript>
<div id="app"></div>
<!-- built files will be auto injected -->
</body>
</html>

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

BIN
static/src/.DS_Store vendored

Binary file not shown.

@ -0,0 +1,23 @@
<template>
<div id="app">
<router-view/>
</div>
</template>
<script>
export default {
name: 'App'
}
</script>
<style>
#app {
font-family: Avenir, Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
margin-top: 60px;
}
</style>

Binary file not shown.

@ -0,0 +1,5 @@
html,body,#app {
height: 100%;
margin: 0;
padding: 0;
}

@ -0,0 +1,9 @@
export default {
data () {
return {
BaseUrl: 'http://127.0.0.1:5000/api',
OriFileBaseUrl: 'http://127.0.0.1:5000/api/get_ori_file/',
ResFileBaseUrl: 'http://127.0.0.1:5000/api/get_res_file/'
}
}
}

@ -0,0 +1,26 @@
export default {
fileMethods: {
// 返回当前登录中的用户的id
saveFileList(filename) {
var fileList = JSON.parse(sessionStorage.getItem('fileList') || '[]')
let tmp = {fileName: filename}
if (fileList.find(val => val.fileName === filename) === undefined) {
fileList.push(tmp)
sessionStorage.setItem('fileList', JSON.stringify(fileList))
}
},
curFileList() {
let fileList = JSON.parse(sessionStorage.getItem('fileList') || '[]')
return fileList
},
isExistFile(filename) {
let fileList = JSON.parse(sessionStorage.getItem('fileList') || '[]')
return fileList.find(val => val.fileName === filename) !== undefined;
}
}
}

@ -0,0 +1,48 @@
export default {
methods: {
isInteger(n) {
return Number.isInteger(n)
},
isFloat(f) {
let tmp = parseInt(f);
if (!Number.isInteger(tmp)){
return false
}
if (Number.isInteger(f)){
return true
}
return f === +f && f !== (f|0);
},
isMaxInteger(n) {
if (n === 'MAX')
return true
return Number.isInteger(n)
},
calculate_res_name(res_name){
var tmp_name = res_name
res_name += '.jpg'
var resList = JSON.parse(sessionStorage.getItem('resList') || '[]')
if (resList.find(val => val.resName === res_name) !== undefined) {
let target = resList.findIndex(val => val.resName === res_name)
resList[target].num ++ ;
tmp_name = tmp_name + resList[target].num.toString()
tmp_name = this.calculate_res_name(tmp_name)
let tmp = {resName: tmp_name, num: 0}
resList.push(tmp)
sessionStorage.setItem('resList', JSON.stringify(resList))
return tmp_name
}
else {
tmp_name += '.jpg'
let tmp = {resName: tmp_name, num: 0}
resList.push(tmp)
sessionStorage.setItem('resList', JSON.stringify(resList))
return tmp_name
}
}
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 106 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 64 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 88 KiB

@ -0,0 +1,167 @@
<template>
<div style="background: #e9e9e9; min-height: 100%">
<el-head>
<Navigation/>
</el-head>
<el-container style="height: 100%; width: 100%; border: 0">
<el-container style="margin-top: 2%; margin-right: 300px; margin-left: 300px">
<el-header style="text-align: center; font-size: 36px">
<div class="content-title">
{{ headmsg }}
</div>
</el-header>
<div class="content">
<el-carousel :interval="4000" type="card" height="400px" indicator-position="outside">
<el-carousel-item v-for="item in imgs" v-bind:key="item">
<img class="bannerImg" :src="item.url">
</el-carousel-item>
</el-carousel>
<el-divider content-position="left">项目小组成员</el-divider>
<el-table :data="tableData" style="width: 1000px; margin-left:30px; font-size: 18px;">
<el-table-column prop="name" label="姓名" width="200" />
<el-table-column prop="schoolID" label="学号" width="200" />
<el-table-column prop="mail" label="邮箱" width="280" />
<el-table-column prop="work" label="主要工作" width="300" />
</el-table>
<el-divider content-position="left">项目主要功能</el-divider>
<p style="text-align: left; font-size: 18px;margin-left: 2em; margin-bottom: 0; line-height: 2em">
项目最终完成难度系数 1.5
<br>
在实现课堂基础要求的图像处理功能之外还通过阅读相关文献借鉴相关开源代码实现了图像的风格迁移功能对项目的现实应用有了较为明确的定位
<br>
项目基础功能
<br>
图片上传
<br>
图像编辑翻转平移旋转放缩
<br>
图像转换图像灰度化二值化
<br>
图像分析灰度直方图彩色直方图
<br>
图像边缘检测RobertSobelLaplacianLoGCanny
<br>
图像增强平滑锐化
<br>
图像形态学腐蚀膨胀开运算闭运算
<br>
图像风格迁移实现了任意风格和任意内容图像的风格迁移功能
</p>
<el-divider content-position="left">项目主要技术栈</el-divider>
<p style="text-align: left; font-size: 18px;margin-left: 2em; margin-bottom: 0; line-height: 2em">
前端VueElementUIVue-Router
<br>
后端FlaskPythonopen-cvtensorflownumpymatplotLibPillow
</p>
<el-divider content-position="left">项目快速启动</el-divider>
<p style="text-align: left; font-size: 18px;margin-left: 2em; margin-bottom: 0; line-height: 2em">
bash run.sh
</p>
</div>
<el-footer height="10px">
<Copyright/>
</el-footer>
</el-container>
</el-container>
</div>
</template>
<script>
import Navigation from "@/components/global/Navigation"
import Copyright from "@/components/global/Copyright"
import Head from "@/components/global/Head"
export default {
name: "Home",
data() {
return {
headmsg: '图像处理系统',
intromsg: '一个简单的图像处理系统。',
tableData : [{
name: '滕思怡',
schoolID : '10190350453',
mail:'tsyxxxka@gmail.com',
work: '基础功能实现与图片风格迁移',
},
{
name: '刘雨杰',
schoolID : '10194900441',
mail:'10194900441@stu.ecnu.edu.cn',
work: '相关应用调研与基础功能实现',
}],
imgs: [
{url: require('../assets/picture/front1.jpg'), link: '/content1'},
{url: require('../assets/picture/front2.jpg'), link: '/content2'},
{url: require('../assets/picture/front3.jpg'), link: '/content3'},
{url: require('../assets/picture/front4.jpg'), link: '/content4'}
]
}
},
methods: {},
components: {
Head,
Navigation,
Copyright
}
}
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
.code {
font-family: Menlo, math;
font-size: 70%;
background: #e9e9e9;
margin-left: 20%;
margin-right: 20%;
border: solid #333333;
}
.code .code_inline {
margin: 2em;
}
.front_env {
font-family: Menlo, math;
font-size: 70%;
background: #e9e9e9;
margin-left: 20%;
margin-right: 20%;
border: solid #333333;
}
.front_env .front_env_inline {
margin: 2em;
}
.back_env {
font-family: Menlo, math;
font-size: 70%;
background: #e9e9e9;
margin-left: 20%;
margin-right: 20%;
border: solid #333333;
margin-bottom: 2em;
}
.back_env .back_env_inline {
margin: 2em;
}
.content {
padding: 25px 25px;
margin: 25px auto;
background-color: #fff;
border-radius: 20px;
border: #e3e1e4 2px solid;
font-size: 18px;
}
.content-title {
color: #335A66;
font-size: 40px;
border: none;
text-align: center;
}
</style>

@ -0,0 +1,14 @@
<template>
<div>
</div>
</template>
<script>
export default {
name: "Copyright"
}
</script>
<style scoped>
</style>

@ -0,0 +1,82 @@
<template>
<div class="upload">
<el-upload
class="upload-demo"
drag
multiple
action="http://127.0.0.1:5000/api/file/upload"
:on-preview="handlePreview"
:on-remove="handleRemove"
:before-upload="beforeAvatarUpload"
:on-success="handleSuccess"
:on-error="handleError"
:file-list="fileList"
list-type="picture">
<i class="el-icon-upload"></i>
<div class="el-upload__text">将文件拖到此处<em>点击上传</em></div>
<div class="el-upload__tip" slot="tip">只能上传jpg文件且不超过2MB</div>
</el-upload>
</div>
</template>
<script>
export default {
name: "FileUpload",
data() {
return {
fileList: [],
uploadResult: ''
};
},
methods: {
beforeAvatarUpload(file) {
const isJPG = file.type === 'image/jpeg';
const isLt2M = file.size / 1024 / 1024 < 2;
if (!isJPG) {
this.$message.error('上传图片只能是 JPG 格式!');
}
if (!isLt2M) {
this.$message.error('上传图片大小不能超过 2MB!');
}
if (this.fileMaintain.isExistFile(file.name)) {
this.$message.error('同名文件已存在!');
}
return isJPG && isLt2M && (!this.fileMaintain.isExistFile(file.name));
},
handleRemove(file, fileList) {
console.log(file, fileList);
},
handlePreview(file) {
console.log(file);
},
handleSuccess(res, file) {
this.fileMaintain.saveFileList(file.name)
this.uploadResult = res
if (this.uploadResult.code === 1) {
this.$message({
message: this.uploadResult.msg,
type: 'success'
});
} else if (this.uploadResult.code === 0) {
this.$message.error(this.uploadResult.msg)
}
},
handleError() {
this.$message.error('上传文件失败');
}
}
}
</script>
<style scoped>
.upload {
margin-top: 70px;
margin-left: 30px;
margin-right: 30px;
margin-bottom: 70px;
}
</style>

@ -0,0 +1,36 @@
<template>
<div class="header">
<div class="head">
<el-button @click="drawer = true" type="primary" style="width:140px;">
上传图片
</el-button>
<el-drawer
:visible.sync="drawer"
:with-header="false">
<FileUpload/>
</el-drawer>
</div>
</div>
</template>
<script>
import FileUpload from "@/components/global/FileUpload"
export default {
name: "Head",
components: {FileUpload},
data() {
return {
drawer: false,
};
}
}
</script>
<style scoped>
.header{
justify-content: left;
margin-top: 20px;
}
</style>

@ -0,0 +1,94 @@
<template>
<div>
<el-menu background-color="#545c64"
text-color="#fff"
mode="horizontal"
default-active="$route.path"
router="true">
<el-menu-item />
<el-menu-item index="/">
<i class="el-icon-s-home"></i>
<span slot="title">主页</span>
</el-menu-item>
<el-submenu>
<template slot="title">
<i class="el-icon-picture-outline"></i>
<span slot="title">图像处理功能</span>
</template>
<el-menu-item index="/basic_func">
<i class="el-icon-picture-outline"></i>
<span slot="title">图像编辑</span>
</el-menu-item>
<el-menu-item index="/histogram">
<i class="el-icon-s-data"></i>
<span slot="title">图像分析</span>
</el-menu-item>
<el-menu-item index="/segmentation">
<i class="el-icon-scissors"></i>
<span slot="title">图像边缘检测</span>
</el-menu-item>
<el-submenu index="/smooth_sharpen">
<template slot="title">
<i class="el-icon-s-operation"></i>
<span slot="title">图像平滑与锐化</span>
</template>
<el-menu-item index="/smooth_sharpen/smooth">图像平滑</el-menu-item>
<el-menu-item index="/smooth_sharpen/sharpen">图像锐化</el-menu-item>
</el-submenu>
<el-menu-item index="/morphological">
<i class="el-icon-magic-stick"></i>
<span slot="title">图像形态学</span>
</el-menu-item>
<el-submenu index="/fix">
<template slot="title">
<i class="el-icon-s-opportunity"></i>
<span slot="title">图像修复</span>
</template>
<el-menu-item index="/fix/noise">添加噪声</el-menu-item>
<el-menu-item index="/fix/repair">图像去噪</el-menu-item>
</el-submenu>
</el-submenu>
<el-menu-item @click.native="drawer = true">
<i class="el-icon-upload"></i>
<span slot="title">图片上传</span>
</el-menu-item>
<el-menu-item index="/style_transfer">
<i class="el-icon-magic-stick"></i>
<span slot="title">图片风格迁移</span>
</el-menu-item>
<el-drawer
:visible.sync="drawer"
:with-header="false">
<FileUpload/>
</el-drawer>
</el-menu>
</div>
</template>
<script>
import FileUpload from "@/components/global/FileUpload"
export default {
name: "Navigation",
components: {FileUpload},
data() {
return {
drawer: false
}
}
}
</script>

@ -0,0 +1,79 @@
<template>
<div style="width: 100%; max-height: 100%;">
<el-button type="text" @click="freshData()" style="margin-top: 15px; margin-left: 30px;">刷新</el-button>
<el-table
ref="multipleTable"
:data="fileList"
tooltip-effect="dark"
height="500"
width="500"
style="width: 100%"
@selection-change="handleSelectionChange">
<el-table-column
type="selection"
align="right"
min-width="20%">
</el-table-column>
<el-table-column
align="left"
prop="fileName"
label="图片名称"
min-width="40%">
</el-table-column>
<el-table-column
align="left"
label="图片预览"
min-width="40%">
<template slot-scope="scope">
<el-popover placement="top-start" title="" trigger="hover">
<img :src="'http://127.0.0.1:5000/api/get_ori_file/' + scope.row.fileName" alt=""
style="width: 150px; height:auto">
<img slot="reference" :src="'http://127.0.0.1:5000/api/get_ori_file/' + scope.row.fileName"
style="width: 70px; height: auto">
</el-popover>
<span>{{ scope.row.title }}</span>
</template>
</el-table-column>
</el-table>
</div>
</template>
<script>
export default {
name: "PictureChooseOne",
data() {
return {
fileList: [],
multipleSelection: []
}
},
created() {
this.fileList = this.fileMaintain.curFileList()
},
methods: {
handleSelectionChange(val) {
this.multipleSelection = val;
for (var i = 0; i < this.multipleSelection.length; i ++) {
this.multipleSelection[i].fileUrl = this.constant.data().OriFileBaseUrl + this.multipleSelection[i].fileName;
}
},
toggleSelection(rows) {
if (rows) {
rows.forEach(row => {
this.$refs.multipleTable.toggleRowSelection(row);
});
} else {
this.$refs.multipleTable.clearSelection();
}
},
freshData() {
this.fileList = this.fileMaintain.curFileList()
}
}
}
</script>
<style scoped>
</style>

File diff suppressed because it is too large Load Diff

@ -0,0 +1,338 @@
<template>
<div class="basic" style="background: #e9e9e9; min-height: 100%">
<el-head>
<Navigation/>
</el-head>
<el-container style="position: absolute; height: 100%; width: 100%; border: 0">
<el-container style="margin-top: 5%; margin-right: 300px; margin-left: 300px">
<el-header style="text-align: center; font-size: 36px">
<div class="heading">
{{ headmsg }}
</div>
</el-header>
<el-main style="text-align: left; font-size: 18px">
{{ intromsg }}
<el-tabs type="border-card" style="margin-top: 30px; min-height: 80%">
<el-tab-pane label="灰度直方图">
<el-steps :active="gray_hist_active" align-center finish-status="success"style="margin-top: 40px">
<el-step title="选择图片"></el-step>
<el-step title="输入参数"></el-step>
<el-step title="处理图片"></el-step>
</el-steps>
<div v-show="gray_hist_active === 0" style="margin-top: 20px;">
<PictureChooseOne ref="gray_histSelection"/>
</div>
<div v-show="gray_hist_active === 1"
style="text-align: center; margin-top: 20px; min-height: 375px; max-height: 375px">
<div style="margin-left: 20%; margin-right: 20%">
<el-form :model="gray_histForm" class="demo-form-inline">
<el-form-item label="输出图像名称"
label-width="30%"
:rules="[
{ required: true, message: '名称不能为空'}
]"
style="align-content: center; margin-left: 10%; margin-right: 10%; width: 60%">
<el-input v-model="gray_histForm.res_name">
<template slot="append">.jpg</template>
</el-input>
</el-form-item>
</el-form>
</div>
</div>
<div v-show="gray_hist_active === 2"
style="text-align: center; margin-top: 20px; min-height: 375px; max-height: 375px">
<div>
<span class="demonstration">原图片</span>
<br>
<img :src="this.displayImg[0].fileUrl" alt=""
style="width: auto; height: auto; max-width: 400px; max-height: 300px; margin-top: 30px">
</div>
</div>
<div v-show="gray_hist_active === 3"
style="text-align: center; margin-top: 20px; min-height: 375px; max-height: 375px">
<div>
<span class="demonstration">结果图片</span>
<br>
<img :src="this.processResult.result_name" alt=""
style="width: auto; height: auto; max-width: 400px; max-height: 300px; margin-top: 30px">
</div>
</div>
<el-button style="margin-left: 70%; margin-top: 30px;" @click="cancel"></el-button>
<el-button v-show="gray_hist_active <= 2" :loading="gray_histLoad" style="margin-left: 10px; margin-top: 10px;"
@click="gray_hist_next">下一步
</el-button>
<el-button v-show="gray_hist_active >= 3" :loading="gray_histLoad" style="margin-left: 10px; margin-top: 10px;"
@click="cancel">完成
</el-button>
</el-tab-pane>
<el-tab-pane label="彩色直方图">
<el-steps :active="bgr_hist_active" align-center finish-status="success"style="margin-top: 40px">
<el-step title="选择图片"></el-step>
<el-step title="输入参数"></el-step>
<el-step title="处理图片"></el-step>
</el-steps>
<div v-show="bgr_hist_active === 0" style="margin-top: 20px;">
<PictureChooseOne ref="bgr_histSelection"/>
</div>
<div v-show="bgr_hist_active === 1"
style="text-align: center; margin-top: 20px; min-height: 375px; max-height: 375px">
<div style="margin-left: 20%; margin-right: 20%">
<el-form :model="bgr_histForm" class="demo-form-inline">
<el-form-item label="输出图像名称"
label-width="30%"
:rules="[
{ required: true, message: '名称不能为空'}
]"
style="align-content: center; margin-left: 10%; margin-right: 10%; width: 60%">
<el-input v-model="bgr_histForm.res_name">
<template slot="append">.jpg</template>
</el-input>
</el-form-item>
</el-form>
</div>
</div>
<div v-show="bgr_hist_active === 2"
style="text-align: center; margin-top: 20px; min-height: 375px; max-height: 375px">
<div>
<span class="demonstration">原图片</span>
<br>
<img :src="this.displayImg[0].fileUrl" alt=""
style="width: auto; height: auto; max-width: 400px; max-height: 300px; margin-top: 30px">
</div>
</div>
<div v-show="bgr_hist_active === 3"
style="text-align: center; margin-top: 20px; min-height: 375px; max-height: 375px">
<div>
<span class="demonstration">结果图片</span>
<br>
<img :src="this.processResult.result_name" alt=""
style="width: auto; height: auto; max-width: 400px; max-height: 300px; margin-top: 30px">
</div>
</div>
<el-button style="margin-left: 70%; margin-top: 30px;" @click="cancel"></el-button>
<el-button v-show="bgr_hist_active <= 2" :loading="bgr_histLoad" style="margin-left: 10px; margin-top: 10px;"
@click="bgr_hist_next">下一步
</el-button>
<el-button v-show="bgr_hist_active >= 3" :loading="bgr_histLoad" style="margin-left: 10px; margin-top: 10px;"
@click="cancel">完成
</el-button>
</el-tab-pane>
</el-tabs>
</el-main>
<el-footer height="10px">
<Copyright/>
</el-footer>
</el-container>
</el-container>
</div>
</template>
<script>
import Navigation from "@/components/global/Navigation"
import Copyright from "@/components/global/Copyright"
import Head from "@/components/global/Head"
import PictureChooseOne from "@/components/global/PictureChooseOne"
export default {
name: "Histogram",
data() {
return {
headmsg: '图像分析',
selection: [],
displayImg: [
{
fileName: '../../../assets/picture/default_pic.jpg'
},
{
fileName: '../../../assets/picture/default_pic.jpg'
}
],
processResult: {
code: '',
message: '',
result_name: '../../../assets/picture/default_pic.jpg'
},
gray_hist_active: 0,
gray_histForm: {
res_name: ''
},
gray_histLoad: false,
bgr_hist_active: 0,
bgr_histForm: {
res_name: ''
},
bgr_histLoad: false
}
},
components: {
Head,
Navigation,
Copyright,
PictureChooseOne
},
methods: {
cancel() {
this.selection = [];
this.displayImg = [{fileName: '../../../assets/picture/default_pic.jpg'}, {fileName: '../../../assets/picture/default_pic.jpg'}];
this.clear_active();
this.gray_histForm.res_name = '';
this.bgr_histForm.res_name = '';
this.gray_histLoad = false;
this.bgr_histLoad = false;
this.processResult = {
code: '',
message: '',
result_name: '../../../assets/picture/default_pic.jpg'
};
},
clear_active() {
this.gray_hist_active = 0;
this.bgr_hist_active = 0;
},
async gray_hist_next() {
let tmp = this.gray_hist_active;
this.clear_active();
this.gray_hist_active = tmp;
if (this.gray_hist_active === 0) {
this.selection = this.$refs["gray_histSelection"].multipleSelection;
this.displayImg[0] = this.selection[0];
if (this.selection.length !== 1) {
this.$alert('选择的图片数量不是一张!', '数量错误', {
confirmButtonText: '确定'
});
return
}
} else if (this.gray_hist_active === 1) {
if (this.gray_histForm.res_name === '') {
this.$alert('输出图像名称不能为空!', '命名错误', {
confirmButtonText: '确定'
});
return
}
this.gray_histForm.res_name = this.utils.calculate_res_name(this.gray_histForm.res_name);
} else if (this.gray_hist_active === 2) {
const axios = require('axios')
this.gray_histLoad = true;
await axios.get(
this.constant.data().BaseUrl + '/histogram/gray', {
params: {
img_name: this.selection[0].fileName,
result_name: this.gray_histForm.res_name
}
}
).then(
(res) => {
this.processResult = res.data;
if (this.processResult.code === '1') {
this.$message({
message: '图片处理成功!',
type: 'success'
});
} else if (this.processResult.code === '2') {
this.$message.error('图片处理成功!');
}
}
)
this.gray_histLoad = false;
} else if (this.gray_hist_active === 3) {
this.gray_hist_active = 0;
return
}
this.gray_hist_active++;
},
async bgr_hist_next() {
let tmp = this.bgr_hist_active;
this.clear_active();
this.bgr_hist_active = tmp;
if (this.bgr_hist_active === 0) {
this.selection = this.$refs["bgr_histSelection"].multipleSelection;
this.displayImg[0] = this.selection[0];
if (this.selection.length !== 1) {
this.$alert('选择的图片数量不是一张!', '数量错误', {
confirmButtonText: '确定'
});
return
}
} else if (this.bgr_hist_active === 1) {
if (this.bgr_histForm.res_name === '') {
this.$alert('输出图像名称不能为空!', '命名错误', {
confirmButtonText: '确定'
});
return
}
this.bgr_histForm.res_name = this.utils.calculate_res_name(this.bgr_histForm.res_name);
} else if (this.bgr_hist_active === 2) {
const axios = require('axios')
this.bgr_histLoad = true;
await axios.get(
this.constant.data().BaseUrl + '/histogram/bgr', {
params: {
img_name: this.selection[0].fileName,
result_name: this.bgr_histForm.res_name
}
}
).then(
(res) => {
this.processResult = res.data;
if (this.processResult.code === '1') {
this.$message({
message: '图片处理成功!',
type: 'success'
});
} else if (this.processResult.code === '2') {
this.$message.error('图片处理成功!');
}
}
)
this.bgr_histLoad = false;
} else if (this.bgr_hist_active === 3) {
this.bgr_hist_active = 0;
return
}
this.bgr_hist_active++;
}
}
}
</script>
<style scoped>
</style>

@ -0,0 +1,754 @@
<template>
<div class="basic" style="background: #e9e9e9; min-height: 100%">
<el-head>
<Navigation/>
</el-head>
<el-container style="position: absolute; height: 100%; width: 100%; border: 0">
<el-container style="margin-top: 5%; margin-right: 300px; margin-left: 300px">
<el-header style="text-align: center; font-size: 36px">
<div class="heading">
{{ headmsg }}
</div>
</el-header>
<el-main style="text-align: left; font-size: 18px">
{{ intromsg }}
<el-tabs type="border-card" style="margin-top: 30px; min-height: 80%">
<el-tab-pane label="腐蚀">
<el-steps :active="erode_active" align-center finish-status="success"style="margin-top: 40px">
<el-step title="选择图片"></el-step>
<el-step title="输入参数"></el-step>
<el-step title="处理图片"></el-step>
</el-steps>
<div v-show="erode_active === 0" style="margin-top: 20px;">
<PictureChooseOne ref="erodeSelection"/>
</div>
<div v-show="erode_active === 1"
style="text-align: center; margin-top: 20px; min-height: 375px; max-height: 375px">
<div style="margin-left: 20%; margin-right: 20%">
<el-form :model="erodeForm" class="demo-form-inline">
<el-form-item label="输出图像名称"
label-width="30%"
:rules="[
{ required: true, message: '名称不能为空'}
]"
style="align-content: center; margin-left: 10%; margin-right: 10%; width: 60%">
<el-input v-model="erodeForm.res_name">
<template slot="append">.jpg</template>
</el-input>
</el-form-item>
<el-form-item label="结构元类型"
label-width="30%"
style="align-content: center; margin-left: 10%; margin-right: 130%; width: 60%">
<el-select v-model="erodeForm.kernel_type" placeholder="请选择结构元类型">
<el-option label="十字形" value="cross"></el-option>
<el-option label="矩形" value="rectangle"></el-option>
</el-select>
</el-form-item>
<el-form-item label="结构元核数"
label-width="30%"
:rules=" [
{ required: true, message:'核数不能为空'},
{ type: 'number', message: '核数必须为数字值'}
]"
style="align-content: center; margin-left: 10%; margin-right: 10%; width: 60%">
<el-input placeholder="奇数推荐3" v-model="erodeForm.kernel_size">
</el-input>
</el-form-item>
</el-form>
</div>
</div>
<div v-show="erode_active === 2"
style="text-align: center; margin-top: 20px; min-height: 375px; max-height: 375px">
<div>
<span class="demonstration">原图片</span>
<br>
<img :src="this.displayImg[0].fileUrl" alt=""
style="width: auto; height: auto; max-width: 400px; max-height: 300px; margin-top: 30px">
</div>
</div>
<div v-show="erode_active === 3"
style="text-align: center; margin-top: 20px; min-height: 375px; max-height: 375px">
<div>
<span class="demonstration">结果图片</span>
<br>
<img :src="this.processResult.result_name" alt=""
style="width: auto; height: auto; max-width: 400px; max-height: 300px; margin-top: 30px">
</div>
</div>
<el-button style="margin-left: 70%; margin-top: 30px;" @click="cancel"></el-button>
<el-button v-show="erode_active <= 2" :loading="erodeLoad" style="margin-left: 10px; margin-top: 10px;"
@click="erode_next">下一步
</el-button>
<el-button v-show="erode_active >= 3" :loading="erodeLoad" style="margin-left: 10px; margin-top: 10px;"
@click="cancel">完成
</el-button>
</el-tab-pane>
<el-tab-pane label="膨胀">
<el-steps :active="dilate_active" align-center finish-status="success"style="margin-top: 40px">
<el-step title="选择图片"></el-step>
<el-step title="输入参数"></el-step>
<el-step title="处理图片"></el-step>
</el-steps>
<div v-show="dilate_active === 0" style="margin-top: 20px;">
<PictureChooseOne ref="dilateSelection"/>
</div>
<div v-show="dilate_active === 1"
style="text-align: center; margin-top: 20px; min-height: 375px; max-height: 375px">
<div style="margin-left: 20%; margin-right: 20%">
<el-form :model="dilateForm" class="demo-form-inline">
<el-form-item label="输出图像名称"
label-width="30%"
:rules="[
{ required: true, message: '名称不能为空'}
]"
style="align-content: center; margin-left: 10%; margin-right: 10%; width: 60%">
<el-input v-model="dilateForm.res_name">
<template slot="append">.jpg</template>
</el-input>
</el-form-item>
<el-form-item label="结构元类型"
label-width="30%"
style="align-content: center; margin-left: 10%; margin-right: 130%; width: 60%">
<el-select v-model="dilateForm.kernel_type" placeholder="请选择结构元类型">
<el-option label="十字形" value="cross"></el-option>
<el-option label="矩形" value="rectangle"></el-option>
</el-select>
</el-form-item>
<el-form-item label="结构元核数"
label-width="30%"
:rules=" [
{ required: true, message:'核数不能为空'},
{ type: 'number', message: '核数必须为数字值'}
]"
style="align-content: center; margin-left: 10%; margin-right: 10%; width: 60%">
<el-input placeholder="奇数推荐3" v-model="dilateForm.kernel_size">
</el-input>
</el-form-item>
</el-form>
</div>
</div>
<div v-show="dilate_active === 2"
style="text-align: center; margin-top: 20px; min-height: 375px; max-height: 375px">
<div>
<span class="demonstration">原图片</span>
<br>
<img :src="this.displayImg[0].fileUrl" alt=""
style="width: auto; height: auto; max-width: 400px; max-height: 300px; margin-top: 30px">
</div>
</div>
<div v-show="dilate_active === 3"
style="text-align: center; margin-top: 20px; min-height: 375px; max-height: 375px">
<div>
<span class="demonstration">结果图片</span>
<br>
<img :src="this.processResult.result_name" alt=""
style="width: auto; height: auto; max-width: 400px; max-height: 300px; margin-top: 30px">
</div>
</div>
<el-button style="margin-left: 70%; margin-top: 30px;" @click="cancel"></el-button>
<el-button v-show="dilate_active <= 2" :loading="dilateLoad" style="margin-left: 10px; margin-top: 10px;"
@click="dilate_next">下一步
</el-button>
<el-button v-show="dilate_active >= 3" :loading="dilateLoad" style="margin-left: 10px; margin-top: 10px;"
@click="cancel">完成
</el-button>
</el-tab-pane>
<el-tab-pane label="开运算">
<el-steps :active="mor_open_active" align-center finish-status="success"style="margin-top: 40px">
<el-step title="选择图片"></el-step>
<el-step title="输入参数"></el-step>
<el-step title="处理图片"></el-step>
</el-steps>
<div v-show="mor_open_active === 0" style="margin-top: 20px;">
<PictureChooseOne ref="mor_openSelection"/>
</div>
<div v-show="mor_open_active === 1"
style="text-align: center; margin-top: 20px; min-height: 375px; max-height: 375px">
<div style="margin-left: 20%; margin-right: 20%">
<el-form :model="mor_openForm" class="demo-form-inline">
<el-form-item label="输出图像名称"
label-width="30%"
:rules="[
{ required: true, message: '名称不能为空'}
]"
style="align-content: center; margin-left: 10%; margin-right: 10%; width: 60%">
<el-input v-model="mor_openForm.res_name">
<template slot="append">.jpg</template>
</el-input>
</el-form-item>
<el-form-item label="结构元类型"
label-width="30%"
style="align-content: center; margin-left: 10%; margin-right: 130%; width: 60%">
<el-select v-model="mor_openForm.kernel_type" placeholder="请选择结构元类型">
<el-option label="十字形" value="cross"></el-option>
<el-option label="矩形" value="rectangle"></el-option>
</el-select>
</el-form-item>
<el-form-item label="结构元核数"
label-width="30%"
:rules=" [
{ required: true, message:'核数不能为空'},
{ type: 'number', message: '核数必须为数字值'}
]"
style="align-content: center; margin-left: 10%; margin-right: 10%; width: 60%">
<el-input placeholder="奇数推荐3" v-model="mor_openForm.kernel_size">
</el-input>
</el-form-item>
</el-form>
</div>
</div>
<div v-show="mor_open_active === 2"
style="text-align: center; margin-top: 20px; min-height: 375px; max-height: 375px">
<div>
<span class="demonstration">原图片</span>
<br>
<img :src="this.displayImg[0].fileUrl" alt=""
style="width: auto; height: auto; max-width: 400px; max-height: 300px; margin-top: 30px">
</div>
</div>
<div v-show="mor_open_active === 3"
style="text-align: center; margin-top: 20px; min-height: 375px; max-height: 375px">
<div>
<span class="demonstration">结果图片</span>
<br>
<img :src="this.processResult.result_name" alt=""
style="width: auto; height: auto; max-width: 400px; max-height: 300px; margin-top: 30px">
</div>
</div>
<el-button style="margin-left: 70%; margin-top: 30px;" @click="cancel"></el-button>
<el-button v-show="mor_open_active <= 2" :loading="mor_openLoad" style="margin-left: 10px; margin-top: 10px;"
@click="mor_open_next">下一步
</el-button>
<el-button v-show="mor_open_active >= 3" :loading="mor_openLoad" style="margin-left: 10px; margin-top: 10px;"
@click="cancel">完成
</el-button>
</el-tab-pane>
<el-tab-pane label="闭运算">
<el-steps :active="mor_close_active" align-center finish-status="success"style="margin-top: 40px">
<el-step title="选择图片"></el-step>
<el-step title="输入参数"></el-step>
<el-step title="处理图片"></el-step>
</el-steps>
<div v-show="mor_close_active === 0" style="margin-top: 20px;">
<PictureChooseOne ref="mor_closeSelection"/>
</div>
<div v-show="mor_close_active === 1"
style="text-align: center; margin-top: 20px; min-height: 375px; max-height: 375px">
<div style="margin-left: 20%; margin-right: 20%">
<el-form :model="mor_closeForm" class="demo-form-inline">
<el-form-item label="输出图像名称"
label-width="30%"
:rules="[
{ required: true, message: '名称不能为空'}
]"
style="align-content: center; margin-left: 10%; margin-right: 10%; width: 60%">
<el-input v-model="mor_closeForm.res_name">
<template slot="append">.jpg</template>
</el-input>
</el-form-item>
<el-form-item label="结构元类型"
label-width="30%"
style="align-content: center; margin-left: 10%; margin-right: 130%; width: 60%">
<el-select v-model="mor_closeForm.kernel_type" placeholder="请选择结构元类型">
<el-option label="十字形" value="cross"></el-option>
<el-option label="矩形" value="rectangle"></el-option>
</el-select>
</el-form-item>
<el-form-item label="结构元核数"
label-width="30%"
:rules=" [
{ required: true, message:'核数不能为空'},
{ type: 'number', message: '核数必须为数字值'}
]"
style="align-content: center; margin-left: 10%; margin-right: 10%; width: 60%">
<el-input placeholder="奇数推荐3" v-model="mor_closeForm.kernel_size">
</el-input>
</el-form-item>
</el-form>
</div>
</div>
<div v-show="mor_close_active === 2"
style="text-align: center; margin-top: 20px; min-height: 375px; max-height: 375px">
<div>
<span class="demonstration">原图片</span>
<br>
<img :src="this.displayImg[0].fileUrl" alt=""
style="width: auto; height: auto; max-width: 400px; max-height: 300px; margin-top: 30px">
</div>
</div>
<div v-show="mor_close_active === 3"
style="text-align: center; margin-top: 20px; min-height: 375px; max-height: 375px">
<div>
<span class="demonstration">结果图片</span>
<br>
<img :src="this.processResult.result_name" alt=""
style="width: auto; height: auto; max-width: 400px; max-height: 300px; margin-top: 30px">
</div>
</div>
<el-button style="margin-left: 70%; margin-top: 30px;" @click="cancel"></el-button>
<el-button v-show="mor_close_active <= 2" :loading="mor_closeLoad" style="margin-left: 10px; margin-top: 10px;"
@click="mor_close_next">下一步
</el-button>
<el-button v-show="mor_close_active >= 3" :loading="mor_closeLoad" style="margin-left: 10px; margin-top: 10px;"
@click="cancel">完成
</el-button>
</el-tab-pane>
</el-tabs>
</el-main>
<el-footer height="10px">
<Copyright/>
</el-footer>
</el-container>
</el-container>
</div>
</template>
<script>
import Navigation from "@/components/global/Navigation"
import Copyright from "@/components/global/Copyright"
import Head from "@/components/global/Head"
import PictureChooseOne from "@/components/global/PictureChooseOne"
export default {
name: "Morphological",
data() {
return {
headmsg: '图像形态学',
selection: [],
displayImg: [
{
fileName: '../../../assets/picture/default_pic.jpg'
},
{
fileName: '../../../assets/picture/default_pic.jpg'
}
],
processResult: {
code: '',
message: '',
result_name: '../../../assets/picture/default_pic.jpg'
},
erode_active: 0,
erodeForm: {
res_name: '',
kernel_type: 'cross',
kernel_size: null
},
erodeLoad: false,
dilate_active: 0,
dilateForm: {
res_name: '',
kernel_type: 'cross',
kernel_size: null
},
dilateLoad: false,
mor_open_active: 0,
mor_openForm: {
res_name: '',
kernel_type: 'cross',
kernel_size: null
},
mor_openLoad: false,
mor_close_active: 0,
mor_closeForm: {
res_name: '',
kernel_type: 'cross',
kernel_size: null
},
mor_closeLoad: false
}
},
components: {
Head,
Navigation,
Copyright,
PictureChooseOne
},
methods: {
cancel() {
this.selection = [];
this.displayImg = [{fileName: '../../../assets/picture/default_pic.jpg'}, {fileName: '../../../assets/picture/default_pic.jpg'}];
this.clear_active();
this.erodeForm.res_name = '';
this.erodeForm.kernel_type = 'cross';
this.erodeForm.kernel_size = null;
this.dilateForm.res_name = '';
this.dilateForm.kernel_type = 'cross';
this.dilateForm.kernel_size = null;
this.mor_openForm.res_name = '';
this.mor_openForm.kernel_type = 'cross';
this.mor_openForm.kernel_size = null;
this.mor_closeForm.res_name = '';
this.mor_closeForm.kernel_type = 'cross';
this.mor_closeForm.kernel_size = null;
this.erodeLoad = false;
this.dilateLoad = false;
this.mor_openLoad = false;
this.mor_closeLoad = false;
this.processResult = {
code: '',
message: '',
result_name: '../../../assets/picture/default_pic.jpg'
};
},
clear_active() {
this.erode_active = 0;
this.dilate_active = 0;
this.mor_open_active = 0;
this.mor_close_active = 0;
},
async erode_next() {
let tmp = this.erode_active;
this.clear_active();
this.erode_active = tmp;
if (this.erode_active === 0) {
this.selection = this.$refs["erodeSelection"].multipleSelection;
this.displayImg[0] = this.selection[0];
if (this.selection.length !== 1) {
this.$alert('选择的图片数量不是一张!', '数量错误', {
confirmButtonText: '确定'
});
return
}
} else if (this.erode_active === 1) {
if ((this.erodeForm.res_name === '') || (this.erodeForm.kernel_size === null)) {
this.$alert('输出图像名称不能为空!<br>结构元核数不能为空!', '参数错误', {
confirmButtonText: '确定',
dangerouslyUseHTMLString: true
});
return
}
this.erodeForm.kernel_size = parseInt(this.erodeForm.kernel_size);
if ((!this.utils.isInteger(this.erodeForm.kernel_size))) {
this.$alert('结构元核数必须为数字!', '参数错误', {
confirmButtonText: '确定'
});
return
}
if ((this.erodeForm.kernel_size % 2 === 0) || (this.erodeForm.kernel_size <= 0)) {
this.$alert('结构元核数必须为正奇数!', '参数错误', {
confirmButtonText: '确定'
});
return
}
this.erodeForm.res_name = this.utils.calculate_res_name(this.erodeForm.res_name);
} else if (this.erode_active === 2) {
const axios = require('axios')
this.erodeLoad = true;
await axios.get(
this.constant.data().BaseUrl + '/morphological/erode', {
params: {
img_name: this.selection[0].fileName,
result_name: this.erodeForm.res_name,
kernel_type: this.erodeForm.kernel_type,
kernel_size: this.erodeForm.kernel_size
}
}
).then(
(res) => {
this.processResult = res.data;
if (this.processResult.code === '1') {
this.$message({
message: '图片处理成功!',
type: 'success'
});
} else if (this.processResult.code === '2') {
this.$message.error('图片处理成功!');
}
}
)
this.erodeLoad = false;
} else if (this.erode_active === 3) {
this.erode_active = 0;
return
}
this.erode_active++;
},
async dilate_next() {
let tmp = this.dilate_active;
this.clear_active();
this.dilate_active = tmp;
if (this.dilate_active === 0) {
this.selection = this.$refs["dilateSelection"].multipleSelection;
this.displayImg[0] = this.selection[0];
if (this.selection.length !== 1) {
this.$alert('选择的图片数量不是一张!', '数量错误', {
confirmButtonText: '确定'
});
return
}
} else if (this.dilate_active === 1) {
if ((this.dilateForm.res_name === '') || (this.dilateForm.kernel_size === null)) {
this.$alert('输出图像名称不能为空!<br>结构元核数不能为空!', '参数错误', {
confirmButtonText: '确定',
dangerouslyUseHTMLString: true
});
return
}
this.dilateForm.kernel_size = parseInt(this.dilateForm.kernel_size);
if ((!this.utils.isInteger(this.dilateForm.kernel_size))) {
this.$alert('结构元核数必须为数字!', '参数错误', {
confirmButtonText: '确定'
});
return
}
if ((this.dilateForm.kernel_size % 2 === 0) || (this.dilateForm.kernel_size <= 0)) {
this.$alert('结构元核数必须为正奇数!', '参数错误', {
confirmButtonText: '确定'
});
return
}
this.dilateForm.res_name = this.utils.calculate_res_name(this.dilateForm.res_name);
} else if (this.dilate_active === 2) {
const axios = require('axios')
this.dilateLoad = true;
await axios.get(
this.constant.data().BaseUrl + '/morphological/dilate', {
params: {
img_name: this.selection[0].fileName,
result_name: this.dilateForm.res_name,
kernel_type: this.dilateForm.kernel_type,
kernel_size: this.dilateForm.kernel_size
}
}
).then(
(res) => {
this.processResult = res.data;
if (this.processResult.code === '1') {
this.$message({
message: '图片处理成功!',
type: 'success'
});
} else if (this.processResult.code === '2') {
this.$message.error('图片处理成功!');
}
}
)
this.dilateLoad = false;
} else if (this.dilate_active === 3) {
this.dilate_active = 0;
return
}
this.dilate_active++;
},
async mor_open_next() {
let tmp = this.mor_open_active;
this.clear_active();
this.mor_open_active = tmp;
if (this.mor_open_active === 0) {
this.selection = this.$refs["mor_openSelection"].multipleSelection;
this.displayImg[0] = this.selection[0];
if (this.selection.length !== 1) {
this.$alert('选择的图片数量不是一张!', '数量错误', {
confirmButtonText: '确定'
});
return
}
} else if (this.mor_open_active === 1) {
if ((this.mor_openForm.res_name === '') || (this.mor_openForm.kernel_size === null)) {
this.$alert('输出图像名称不能为空!<br>结构元核数不能为空!', '参数错误', {
confirmButtonText: '确定',
dangerouslyUseHTMLString: true
});
return
}
this.mor_openForm.kernel_size = parseInt(this.mor_openForm.kernel_size);
if ((!this.utils.isInteger(this.mor_openForm.kernel_size))) {
this.$alert('结构元核数必须为数字!', '参数错误', {
confirmButtonText: '确定'
});
return
}
if ((this.mor_openForm.kernel_size % 2 === 0) || (this.mor_openForm.kernel_size <= 0)) {
this.$alert('结构元核数必须为正奇数!', '参数错误', {
confirmButtonText: '确定'
});
return
}
this.mor_openForm.res_name = this.utils.calculate_res_name(this.mor_openForm.res_name);
} else if (this.mor_open_active === 2) {
const axios = require('axios')
this.mor_openLoad = true;
await axios.get(
this.constant.data().BaseUrl + '/morphological/mor_open', {
params: {
img_name: this.selection[0].fileName,
result_name: this.mor_openForm.res_name,
kernel_type: this.mor_openForm.kernel_type,
kernel_size: this.mor_openForm.kernel_size
}
}
).then(
(res) => {
this.processResult = res.data;
if (this.processResult.code === '1') {
this.$message({
message: '图片处理成功!',
type: 'success'
});
} else if (this.processResult.code === '2') {
this.$message.error('图片处理成功!');
}
}
)
this.mor_openLoad = false;
} else if (this.mor_open_active === 3) {
this.mor_open_active = 0;
return
}
this.mor_open_active++;
},
async mor_close_next() {
let tmp = this.mor_close_active;
this.clear_active();
this.mor_close_active = tmp;
if (this.mor_close_active === 0) {
this.selection = this.$refs["mor_closeSelection"].multipleSelection;
this.displayImg[0] = this.selection[0];
if (this.selection.length !== 1) {
this.$alert('选择的图片数量不是一张!', '数量错误', {
confirmButtonText: '确定'
});
return
}
} else if (this.mor_close_active === 1) {
if ((this.mor_closeForm.res_name === '') || (this.mor_closeForm.kernel_size === null)) {
this.$alert('输出图像名称不能为空!<br>结构元核数不能为空!', '参数错误', {
confirmButtonText: '确定',
dangerouslyUseHTMLString: true
});
return
}
this.mor_closeForm.kernel_size = parseInt(this.mor_closeForm.kernel_size);
if ((!this.utils.isInteger(this.mor_closeForm.kernel_size))) {
this.$alert('结构元核数必须为数字!', '参数错误', {
confirmButtonText: '确定'
});
return
}
if ((this.mor_closeForm.kernel_size % 2 === 0) || (this.mor_closeForm.kernel_size <= 0)) {
this.$alert('结构元核数必须为正奇数!', '参数错误', {
confirmButtonText: '确定'
});
return
}
this.mor_closeForm.res_name = this.utils.calculate_res_name(this.mor_closeForm.res_name);
} else if (this.mor_close_active === 2) {
const axios = require('axios')
this.mor_closeLoad = true;
await axios.get(
this.constant.data().BaseUrl + '/morphological/mor_close', {
params: {
img_name: this.selection[0].fileName,
result_name: this.mor_closeForm.res_name,
kernel_type: this.mor_closeForm.kernel_type,
kernel_size: this.mor_closeForm.kernel_size
}
}
).then(
(res) => {
this.processResult = res.data;
if (this.processResult.code === '1') {
this.$message({
message: '图片处理成功!',
type: 'success'
});
} else if (this.processResult.code === '2') {
this.$message.error('图片处理成功!');
}
}
)
this.mor_closeLoad = false;
} else if (this.mor_close_active === 3) {
this.mor_close_active = 0;
return
}
this.mor_close_active++;
}
}
}
</script>
<style scoped>
</style>

@ -0,0 +1,429 @@
<template>
<div class="basic" style="background: #e9e9e9; min-height: 100%">
<el-head>
<Navigation/>
</el-head>
<el-container style="position: absolute; height: 100%; width: 100%; border: 0">
<el-container style="margin-top: 5%; margin-right: 300px; margin-left: 300px">
<el-header style="text-align: center; font-size: 36px">
<div class="heading">
{{ headmsg }}
</div>
</el-header>
<el-main style="text-align: left; font-size: 18px">
{{ intromsg }}
<el-tabs type="border-card" style="margin-top: 30px; min-height: 80%">
<el-tab-pane label="高斯噪声">
<el-steps :active="gauss_noise_active" align-center finish-status="success"style="margin-top: 40px">
<el-step title="选择图片"></el-step>
<el-step title="输入参数"></el-step>
<el-step title="处理图片"></el-step>
</el-steps>
<div v-show="gauss_noise_active === 0" style="margin-top: 20px;">
<PictureChooseOne ref="gauss_noiseSelection"/>
</div>
<div v-show="gauss_noise_active === 1"
style="text-align: center; margin-top: 20px; min-height: 375px; max-height: 375px">
<div style="margin-left: 20%; margin-right: 20%">
<el-form :model="gauss_noiseForm" class="demo-form-inline">
<el-form-item label="输出图像名称"
label-width="30%"
:rules="[
{ required: true, message: '名称不能为空'}
]"
style="align-content: center; margin-left: 10%; margin-right: 10%; width: 60%">
<el-input v-model="gauss_noiseForm.res_name">
<template slot="append">.jpg</template>
</el-input>
</el-form-item>
</el-form>
</div>
</div>
<div v-show="gauss_noise_active === 2"
style="text-align: center; margin-top: 20px; min-height: 375px; max-height: 375px">
<div>
<span class="demonstration">原图片</span>
<br>
<img :src="this.displayImg[0].fileUrl" alt=""
style="width: auto; height: auto; max-width: 400px; max-height: 300px; margin-top: 30px">
</div>
</div>
<div v-show="gauss_noise_active === 3"
style="text-align: center; margin-top: 20px; min-height: 375px; max-height: 375px">
<div>
<span class="demonstration">结果图片</span>
<br>
<img :src="this.processResult.result_name" alt=""
style="width: auto; height: auto; max-width: 400px; max-height: 300px; margin-top: 30px">
</div>
</div>
<el-button style="margin-left: 70%; margin-top: 30px;" @click="cancel"></el-button>
<el-button v-show="gauss_noise_active <= 2" :loading="gauss_noiseLoad" style="margin-left: 10px; margin-top: 10px;"
@click="gauss_noise_next">下一步
</el-button>
<el-button v-show="gauss_noise_active >= 3" :loading="gauss_noiseLoad" style="margin-left: 10px; margin-top: 10px;"
@click="cancel">完成
</el-button>
</el-tab-pane>
<el-tab-pane label="椒盐噪声">
<el-steps :active="sault_pepper_noise_active" align-center finish-status="success"style="margin-top: 40px">
<el-step title="选择图片"></el-step>
<el-step title="输入参数"></el-step>
<el-step title="处理图片"></el-step>
</el-steps>
<div v-show="sault_pepper_noise_active === 0" style="margin-top: 20px;">
<PictureChooseOne ref="sault_pepper_noiseSelection"/>
</div>
<div v-show="sault_pepper_noise_active === 1"
style="text-align: center; margin-top: 20px; min-height: 375px; max-height: 375px">
<div style="margin-left: 20%; margin-right: 20%">
<el-form :model="sault_pepper_noiseForm" class="demo-form-inline">
<el-form-item label="输出图像名称"
label-width="30%"
:rules="[
{ required: true, message: '名称不能为空'}
]"
style="align-content: center; margin-left: 10%; margin-right: 10%; width: 60%">
<el-input v-model="sault_pepper_noiseForm.res_name">
<template slot="append">.jpg</template>
</el-input>
</el-form-item>
<el-form-item label="胡椒噪声范围"
:rules="[
{ required: true, message: '范围值不能为空'}
]"
style="align-content: center; margin-left: 10%; margin-right: 10%; width:80%">
<el-col :span="7">
<el-input placeholder="最小值" v-model="sault_pepper_noiseForm.ran_x1">
</el-input>
</el-col>
<el-col class="line" :span="2">-</el-col>
<el-col :span="7">
<el-input placeholder="无穷大输入'MAX'" v-model="sault_pepper_noiseForm.ran_y1">
</el-input>
</el-col>
</el-form-item>
<el-form-item label="食盐噪声范围"
:rules="[
{ required: true, message: '范围值不能为空'}
]"
style="align-content: center; margin-left: 10%; margin-right: 10%; width:80%">
<el-col :span="7">
<el-input placeholder="最小值" v-model="sault_pepper_noiseForm.ran_x2">
</el-input>
</el-col>
<el-col class="line" :span="2">-</el-col>
<el-col :span="7">
<el-input placeholder="无穷大输入'MAX'" v-model="sault_pepper_noiseForm.ran_y2">
</el-input>
</el-col>
</el-form-item>
</el-form>
</div>
</div>
<div v-show="sault_pepper_noise_active === 2"
style="text-align: center; margin-top: 20px; min-height: 375px; max-height: 375px">
<div>
<span class="demonstration">原图片</span>
<br>
<img :src="this.displayImg[0].fileUrl" alt=""
style="width: auto; height: auto; max-width: 400px; max-height: 300px; margin-top: 30px">
</div>
</div>
<div v-show="sault_pepper_noise_active === 3"
style="text-align: center; margin-top: 20px; min-height: 375px; max-height: 375px">
<div>
<span class="demonstration">结果图片</span>
<br>
<img :src="this.processResult.result_name" alt=""
style="width: auto; height: auto; max-width: 400px; max-height: 300px; margin-top: 30px">
</div>
</div>
<el-button style="margin-left: 70%; margin-top: 30px;" @click="cancel"></el-button>
<el-button v-show="sault_pepper_noise_active <= 2" :loading="sault_pepper_noiseLoad" style="margin-left: 10px; margin-top: 10px;"
@click="sault_pepper_noise_next">下一步
</el-button>
<el-button v-show="sault_pepper_noise_active >= 3" :loading="sault_pepper_noiseLoad" style="margin-left: 10px; margin-top: 10px;"
@click="cancel">完成
</el-button>
</el-tab-pane>
</el-tabs>
</el-main>
<el-footer height="10px">
<Copyright/>
</el-footer>
</el-container>
</el-container>
</div>
</template>
<script>
import Navigation from "@/components/global/Navigation"
import Copyright from "@/components/global/Copyright"
import Head from "@/components/global/Head"
import PictureChooseOne from "@/components/global/PictureChooseOne"
export default {
name: "Noise",
data() {
return {
headmsg: '添加噪声',
selection: [],
displayImg: [
{
fileName: '../../../assets/picture/default_pic.jpg'
},
{
fileName: '../../../assets/picture/default_pic.jpg'
}
],
processResult: {
code: '',
message: '',
result_name: '../../../assets/picture/default_pic.jpg'
},
gauss_noise_active: 0,
gauss_noiseForm: {
res_name: ''
},
gauss_noiseLoad: false,
sault_pepper_noise_active: 0,
sault_pepper_noiseForm: {
res_name: '',
ran_x1: null,
ran_y1: null,
ran_x2: null,
ran_y2: null
},
sault_pepper_noiseLoad: false
}
},
components: {
Head,
Navigation,
Copyright,
PictureChooseOne
},
methods: {
cancel() {
this.selection = [];
this.displayImg = [{fileName: '../../../assets/picture/default_pic.jpg'}, {fileName: '../../../assets/picture/default_pic.jpg'}];
this.clear_active();
this.gauss_noiseForm.res_name = '';
this.sault_pepper_noiseForm.res_name = '';
this.sault_pepper_noiseForm.ran_x1 = null;
this.sault_pepper_noiseForm.ran_y1 = null;
this.sault_pepper_noiseForm.ran_x2 = null;
this.sault_pepper_noiseForm.ran_y2 = null;
this.gauss_noiseLoad = false;
this.sault_pepper_noiseLoad = false;
this.processResult = {
code: '',
message: '',
result_name: '../../../assets/picture/default_pic.jpg'
};
},
clear_active() {
this.gauss_noise_active = 0;
this.sault_pepper_noise_active = 0;
},
async gauss_noise_next() {
let tmp = this.gauss_noise_active;
this.clear_active();
this.gauss_noise_active = tmp;
if (this.gauss_noise_active === 0) {
this.selection = this.$refs["gauss_noiseSelection"].multipleSelection;
this.displayImg[0] = this.selection[0];
if (this.selection.length !== 1) {
this.$alert('选择的图片数量不是一张!', '数量错误', {
confirmButtonText: '确定'
});
return
}
} else if (this.gauss_noise_active === 1) {
if (this.gauss_noiseForm.res_name === '') {
this.$alert('输出图像名称不能为空!', '命名错误', {
confirmButtonText: '确定'
});
return
}
this.gauss_noiseForm.res_name = this.utils.calculate_res_name(this.gauss_noiseForm.res_name);
} else if (this.gauss_noise_active === 2) {
const axios = require('axios')
this.gauss_noiseLoad = true;
await axios.get(
this.constant.data().BaseUrl + '/repair/gauss_noise', {
params: {
img_name: this.selection[0].fileName,
result_name: this.gauss_noiseForm.res_name
}
}
).then(
(res) => {
this.processResult = res.data;
if (this.processResult.code === '1') {
this.$message({
message: '图片处理成功!',
type: 'success'
});
} else if (this.processResult.code === '2') {
this.$message.error('图片处理成功!');
}
}
)
this.gauss_noiseLoad = false;
} else if (this.gauss_noise_active === 3) {
this.gauss_noise_active = 0;
return
}
this.gauss_noise_active++;
},
async sault_pepper_noise_next() {
let tmp = this.sault_pepper_noise_active;
this.clear_active();
this.sault_pepper_noise_active = tmp;
if (this.sault_pepper_noise_active === 0) {
this.selection = this.$refs["sault_pepper_noiseSelection"].multipleSelection;
this.displayImg[0] = this.selection[0];
if (this.selection.length !== 1) {
this.$alert('选择的图片数量不是一张!', '数量错误', {
confirmButtonText: '确定'
});
return
}
} else if (this.sault_pepper_noise_active === 1) {
if ((this.sault_pepper_noiseForm.res_name === '') || (this.sault_pepper_noiseForm.ran_x1 === null) || (this.sault_pepper_noiseForm.ran_y1 === null) || (this.sault_pepper_noiseForm.ran_x2 === null) || (this.sault_pepper_noiseForm.ran_y2 === null)) {
this.$alert('输出图像名称不能为空!<br>噪声范围不能为空!', '命名错误', {
confirmButtonText: '确定',
dangerouslyUseHTMLString: true
});
return
}
var tmp1;
var tmp2;
if (this.sault_pepper_noiseForm.ran_y1 !== 'MAX'){
this.sault_pepper_noiseForm.ran_y1 = parseInt(this.sault_pepper_noiseForm.ran_y1)
tmp1 = this.sault_pepper_noiseForm.ran_y1;
}
else {
tmp1 = Number.MAX_VALUE;
}
if (this.sault_pepper_noiseForm.ran_y2 !== 'MAX'){
this.sault_pepper_noiseForm.ran_y2 = parseInt(this.sault_pepper_noiseForm.ran_y2)
tmp2 = this.sault_pepper_noiseForm.ran_y2;
}
else {
tmp2 = Number.MAX_VALUE;
}
this.sault_pepper_noiseForm.ran_x1 = parseInt(this.sault_pepper_noiseForm.ran_x1)
this.sault_pepper_noiseForm.ran_x2 = parseInt(this.sault_pepper_noiseForm.ran_x2)
if((!this.utils.isMaxInteger(this.sault_pepper_noiseForm.ran_x1)) || (!this.utils.isMaxInteger(this.sault_pepper_noiseForm.ran_y1)) || (!this.utils.isMaxInteger(this.sault_pepper_noiseForm.ran_x2)) || (!this.utils.isMaxInteger(this.sault_pepper_noiseForm.ran_y2))) {
this.$alert('噪声范围必须为数字!', '参数错误', {
confirmButtonText: '确定'
});
return
}
if((this.sault_pepper_noiseForm.ran_x1 < 0) || (tmp1 < 0) || (this.sault_pepper_noiseForm.ran_x2 < 0) || (tmp2 < 0)) {
this.$alert('噪声范围不能为负!', '参数错误', {
confirmButtonText: '确定'
});
return
}
if((this.sault_pepper_noiseForm.ran_x1 > tmp1) || (this.sault_pepper_noiseForm.ran_x2 > tmp2)) {
this.$alert('最小值不得大于最大值!', '参数错误', {
confirmButtonText: '确定'
});
return
}
this.sault_pepper_noiseForm.res_name = this.utils.calculate_res_name(this.sault_pepper_noiseForm.res_name);
} else if (this.sault_pepper_noise_active === 2) {
const axios = require('axios')
this.sault_pepper_noiseLoad = true;
await axios.get(
this.constant.data().BaseUrl + '/repair/sault_pepper_noise', {
params: {
img_name: this.selection[0].fileName,
result_name: this.sault_pepper_noiseForm.res_name,
ran_x1: this.sault_pepper_noiseForm.ran_x1,
ran_y1: this.sault_pepper_noiseForm.ran_y1,
ran_x2: this.sault_pepper_noiseForm.ran_x2,
ran_y2: this.sault_pepper_noiseForm.ran_y2
}
}
).then(
(res) => {
this.processResult = res.data;
if (this.processResult.code === '1') {
this.$message({
message: '图片处理成功!',
type: 'success'
});
} else if (this.processResult.code === '2') {
this.$message.error('图片处理成功!');
}
}
)
this.sault_pepper_noiseLoad = false;
} else if (this.sault_pepper_noise_active === 3) {
this.sault_pepper_noise_active = 0;
return
}
this.sault_pepper_noise_active++;
}
}
}
</script>
<style scoped>
</style>

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

@ -0,0 +1,893 @@
<template>
<div class="basic" style="background: #e9e9e9; min-height: 100%">
<el-head>
<Navigation/>
</el-head>
<el-container style="position: absolute; height: 100%; width: 100%; border: 0">
<el-container style="margin-top: 5%; margin-right: 300px; margin-left: 300px">
<el-header style="text-align: center; font-size: 36px">
<div class="heading">
{{ headmsg }}
</div>
</el-header>
<el-main style="text-align: left; font-size: 18px">
{{ intromsg }}
<el-tabs type="border-card" style="margin-top: 30px; min-height: 80%">
<el-tab-pane label="领域平均法">
<el-steps :active="neighbour_average_active" align-center finish-status="success"style="margin-top: 40px">
<el-step title="选择图片"></el-step>
<el-step title="输入参数"></el-step>
<el-step title="处理图片"></el-step>
</el-steps>
<div v-show="neighbour_average_active === 0" style="margin-top: 20px;">
<PictureChooseOne ref="neighbour_averageSelection"/>
</div>
<div v-show="neighbour_average_active === 1"
style="text-align: center; margin-top: 20px; min-height: 375px; max-height: 375px">
<div style="margin-left: 20%; margin-right: 20%">
<el-form :model="neighbour_averageForm" class="demo-form-inline">
<el-form-item label="输出图像名称"
label-width="30%"
:rules="[
{ required: true, message: '名称不能为空'}
]"
style="align-content: center; margin-left: 10%; margin-right: 10%; width: 60%">
<el-input v-model="neighbour_averageForm.res_name">
<template slot="append">.jpg</template>
</el-input>
</el-form-item>
<el-form-item label="核数"
label-width="30%"
:rules=" [
{ required: true, message:'核数不能为空'},
{ type: 'number', message: '核数必须为数字值'}
]"
style="align-content: center; margin-left: 10%; margin-right: 10%; width: 60%">
<el-input placeholder="奇数推荐3" v-model="neighbour_averageForm.kernel_size">
</el-input>
</el-form-item>
</el-form>
</div>
</div>
<div v-show="neighbour_average_active === 2"
style="text-align: center; margin-top: 20px; min-height: 375px; max-height: 375px">
<div>
<span class="demonstration">原图片</span>
<br>
<img :src="this.displayImg[0].fileUrl" alt=""
style="width: auto; height: auto; max-width: 400px; max-height: 300px; margin-top: 30px">
</div>
</div>
<div v-show="neighbour_average_active === 3"
style="text-align: center; margin-top: 20px; min-height: 375px; max-height: 375px">
<div>
<span class="demonstration">结果图片</span>
<br>
<img :src="this.processResult.result_name" alt=""
style="width: auto; height: auto; max-width: 400px; max-height: 300px; margin-top: 30px">
</div>
</div>
<el-button style="margin-left: 70%; margin-top: 30px;" @click="cancel"></el-button>
<el-button v-show="neighbour_average_active <= 2" :loading="neighbour_averageLoad" style="margin-left: 10px; margin-top: 10px;"
@click="neighbour_average_next">下一步
</el-button>
<el-button v-show="neighbour_average_active >= 3" :loading="neighbour_averageLoad" style="margin-left: 10px; margin-top: 10px;"
@click="cancel">完成
</el-button>
</el-tab-pane>
<el-tab-pane label="中值滤波法">
<el-steps :active="median_filter_active" align-center finish-status="success"style="margin-top: 40px">
<el-step title="选择图片"></el-step>
<el-step title="输入参数"></el-step>
<el-step title="处理图片"></el-step>
</el-steps>
<div v-show="median_filter_active === 0" style="margin-top: 20px;">
<PictureChooseOne ref="median_filterSelection"/>
</div>
<div v-show="median_filter_active === 1"
style="text-align: center; margin-top: 20px; min-height: 375px; max-height: 375px">
<div style="margin-left: 20%; margin-right: 20%">
<el-form :model="median_filterForm" class="demo-form-inline">
<el-form-item label="输出图像名称"
label-width="30%"
:rules="[
{ required: true, message: '名称不能为空'}
]"
style="align-content: center; margin-left: 10%; margin-right: 10%; width: 60%">
<el-input v-model="median_filterForm.res_name">
<template slot="append">.jpg</template>
</el-input>
</el-form-item>
<el-form-item label="核数"
label-width="30%"
:rules=" [
{ required: true, message:'核数不能为空'},
{ type: 'number', message: '核数必须为数字值'}
]"
style="align-content: center; margin-left: 10%; margin-right: 10%; width: 60%">
<el-input placeholder="奇数推荐3" v-model="median_filterForm.kernel_size">
</el-input>
</el-form-item>
</el-form>
</div>
</div>
<div v-show="median_filter_active === 2"
style="text-align: center; margin-top: 20px; min-height: 375px; max-height: 375px">
<div>
<span class="demonstration">原图片</span>
<br>
<img :src="this.displayImg[0].fileUrl" alt=""
style="width: auto; height: auto; max-width: 400px; max-height: 300px; margin-top: 30px">
</div>
</div>
<div v-show="median_filter_active === 3"
style="text-align: center; margin-top: 20px; min-height: 375px; max-height: 375px">
<div>
<span class="demonstration">结果图片</span>
<br>
<img :src="this.processResult.result_name" alt=""
style="width: auto; height: auto; max-width: 400px; max-height: 300px; margin-top: 30px">
</div>
</div>
<el-button style="margin-left: 70%; margin-top: 30px;" @click="cancel"></el-button>
<el-button v-show="median_filter_active <= 2" :loading="median_filterLoad" style="margin-left: 10px; margin-top: 10px;"
@click="median_filter_next">下一步
</el-button>
<el-button v-show="median_filter_active >= 3" :loading="median_filterLoad" style="margin-left: 10px; margin-top: 10px;"
@click="cancel">完成
</el-button>
</el-tab-pane>
<el-tab-pane label="理想低通滤波器">
<el-steps :active="ideal_filter_active" align-center finish-status="success"style="margin-top: 40px">
<el-step title="选择图片"></el-step>
<el-step title="输入参数"></el-step>
<el-step title="处理图片"></el-step>
</el-steps>
<div v-show="ideal_filter_active === 0" style="margin-top: 20px;">
<PictureChooseOne ref="ideal_filterSelection"/>
</div>
<div v-show="ideal_filter_active === 1"
style="text-align: center; margin-top: 20px; min-height: 375px; max-height: 375px">
<div style="margin-left: 20%; margin-right: 20%">
<el-form :model="ideal_filterForm" class="demo-form-inline">
<el-form-item label="输出图像名称"
label-width="30%"
:rules="[
{ required: true, message: '名称不能为空'}
]"
style="align-content: center; margin-left: 10%; margin-right: 10%; width: 60%">
<el-input v-model="ideal_filterForm.res_name">
<template slot="append">.jpg</template>
</el-input>
</el-form-item>
<el-form-item label="阈值"
label-width="30%"
:rules=" [
{ required: true, message:'阈值不能为空'},
{ type: 'number', message: '阈值必须为数字值'}
]"
style="align-content: center; margin-left: 10%; margin-right: 10%; width: 60%">
<el-input placeholder="0255" v-model="ideal_filterForm.d0">
</el-input>
</el-form-item>
</el-form>
</div>
</div>
<div v-show="ideal_filter_active === 2"
style="text-align: center; margin-top: 20px; min-height: 375px; max-height: 375px">
<div>
<span class="demonstration">原图片</span>
<br>
<img :src="this.displayImg[0].fileUrl" alt=""
style="width: auto; height: auto; max-width: 400px; max-height: 300px; margin-top: 30px">
</div>
</div>
<div v-show="ideal_filter_active === 3"
style="text-align: center; margin-top: 20px; min-height: 375px; max-height: 375px">
<div>
<span class="demonstration">结果图片</span>
<br>
<img :src="this.processResult.result_name" alt=""
style="width: auto; height: auto; max-width: 400px; max-height: 300px; margin-top: 30px">
</div>
</div>
<el-button style="margin-left: 70%; margin-top: 30px;" @click="cancel"></el-button>
<el-button v-show="ideal_filter_active <= 2" :loading="ideal_filterLoad" style="margin-left: 10px; margin-top: 10px;"
@click="ideal_filter_next">下一步
</el-button>
<el-button v-show="ideal_filter_active >= 3" :loading="ideal_filterLoad" style="margin-left: 10px; margin-top: 10px;"
@click="cancel">完成
</el-button>
</el-tab-pane>
<el-tab-pane label="巴特沃斯低通滤波器">
<el-steps :active="barte_filter_active" align-center finish-status="success"style="margin-top: 40px">
<el-step title="选择图片"></el-step>
<el-step title="输入参数"></el-step>
<el-step title="处理图片"></el-step>
</el-steps>
<div v-show="barte_filter_active === 0" style="margin-top: 20px;">
<PictureChooseOne ref="barte_filterSelection"/>
</div>
<div v-show="barte_filter_active === 1"
style="text-align: center; margin-top: 20px; min-height: 375px; max-height: 375px">
<div style="margin-left: 20%; margin-right: 20%">
<el-form :model="barte_filterForm" class="demo-form-inline">
<el-form-item label="输出图像名称"
label-width="30%"
:rules="[
{ required: true, message: '名称不能为空'}
]"
style="align-content: center; margin-left: 10%; margin-right: 10%; width: 60%">
<el-input v-model="barte_filterForm.res_name">
<template slot="append">.jpg</template>
</el-input>
</el-form-item>
<el-form-item label="阈值"
label-width="30%"
:rules=" [
{ required: true, message:'阈值不能为空'},
{ type: 'number', message: '阈值必须为数字值'}
]"
style="align-content: center; margin-left: 10%; margin-right: 10%; width: 60%">
<el-input placeholder="0255" v-model="barte_filterForm.d0">
</el-input>
</el-form-item>
<el-form-item label="阶数"
label-width="30%"
:rules=" [
{ required: true, message:'阶数不能为空'},
{ type: 'number', message: '阶数必须为数字值'}
]"
style="align-content: center; margin-left: 10%; margin-right: 10%; width: 60%">
<el-input v-model="barte_filterForm.rank">
</el-input>
</el-form-item>
</el-form>
</div>
</div>
<div v-show="barte_filter_active === 2"
style="text-align: center; margin-top: 20px; min-height: 375px; max-height: 375px">
<div>
<span class="demonstration">原图片</span>
<br>
<img :src="this.displayImg[0].fileUrl" alt=""
style="width: auto; height: auto; max-width: 400px; max-height: 300px; margin-top: 30px">
</div>
</div>
<div v-show="barte_filter_active === 3"
style="text-align: center; margin-top: 20px; min-height: 375px; max-height: 375px">
<div>
<span class="demonstration">结果图片</span>
<br>
<img :src="this.processResult.result_name" alt=""
style="width: auto; height: auto; max-width: 400px; max-height: 300px; margin-top: 30px">
</div>
</div>
<el-button style="margin-left: 70%; margin-top: 30px;" @click="cancel"></el-button>
<el-button v-show="barte_filter_active <= 2" :loading="barte_filterLoad" style="margin-left: 10px; margin-top: 10px;"
@click="barte_filter_next">下一步
</el-button>
<el-button v-show="barte_filter_active >= 3" :loading="barte_filterLoad" style="margin-left: 10px; margin-top: 10px;"
@click="cancel">完成
</el-button>
</el-tab-pane>
<el-tab-pane label="高斯低通滤波器">
<el-steps :active="exp_filter_active" align-center finish-status="success" style="margin-top: 40px">
<el-step title="选择图片"></el-step>
<el-step title="输入参数"></el-step>
<el-step title="处理图片"></el-step>
</el-steps>
<div v-show="exp_filter_active === 0" style="margin-top: 20px;">
<PictureChooseOne ref="exp_filterSelection"/>
</div>
<div v-show="exp_filter_active === 1"
style="text-align: center; margin-top: 20px; min-height: 375px; max-height: 375px">
<div style="margin-left: 20%; margin-right: 20%">
<el-form :model="exp_filterForm" class="demo-form-inline">
<el-form-item label="输出图像名称"
label-width="30%"
:rules="[
{ required: true, message: '名称不能为空'}
]"
style="align-content: center; margin-left: 10%; margin-right: 10%; width: 60%">
<el-input v-model="exp_filterForm.res_name">
<template slot="append">.jpg</template>
</el-input>
</el-form-item>
<el-form-item label="阈值"
label-width="30%"
:rules=" [
{ required: true, message:'阈值不能为空'},
{ type: 'number', message: '阈值必须为数字值'}
]"
style="align-content: center; margin-left: 10%; margin-right: 10%; width: 60%">
<el-input placeholder="0255" v-model="exp_filterForm.d0">
</el-input>
</el-form-item>
<el-form-item label="阶数"
label-width="30%"
:rules=" [
{ required: true, message:'阶数不能为空'},
{ type: 'number', message: '阶数必须为数字值'}
]"
style="align-content: center; margin-left: 10%; margin-right: 10%; width: 60%">
<el-input v-model="exp_filterForm.rank">
</el-input>
</el-form-item>
</el-form>
</div>
</div>
<div v-show="exp_filter_active === 2"
style="text-align: center; margin-top: 20px; min-height: 375px; max-height: 375px">
<div>
<span class="demonstration">原图片</span>
<br>
<img :src="this.displayImg[0].fileUrl" alt=""
style="width: auto; height: auto; max-width: 400px; max-height: 300px; margin-top: 30px">
</div>
</div>
<div v-show="exp_filter_active === 3"
style="text-align: center; margin-top: 20px; min-height: 375px; max-height: 375px">
<div>
<span class="demonstration">结果图片</span>
<br>
<img :src="this.processResult.result_name" alt=""
style="width: auto; height: auto; max-width: 400px; max-height: 300px; margin-top: 30px">
</div>
</div>
<el-button style="margin-left: 70%; margin-top: 30px;" @click="cancel"></el-button>
<el-button v-show="exp_filter_active <= 2" :loading="exp_filterLoad" style="margin-left: 10px; margin-top: 10px;"
@click="exp_filter_next">下一步
</el-button>
<el-button v-show="exp_filter_active >= 3" :loading="exp_filterLoad" style="margin-left: 10px; margin-top: 10px;"
@click="cancel">完成
</el-button>
</el-tab-pane>
</el-tabs>
</el-main>
<el-footer height="10px">
<Copyright/>
</el-footer>
</el-container>
</el-container>
</div>
</template>
<script>
import Navigation from "@/components/global/Navigation"
import Copyright from "@/components/global/Copyright"
import Head from "@/components/global/Head"
import PictureChooseOne from "@/components/global/PictureChooseOne"
export default {
name: "Smooth",
data() {
return {
headmsg: '图像平滑',
selection: [],
displayImg: [
{
fileName: '../../../assets/picture/default_pic.jpg'
},
{
fileName: '../../../assets/picture/default_pic.jpg'
}
],
processResult: {
code: '',
message: '',
result_name: '../../../assets/picture/default_pic.jpg'
},
neighbour_average_active: 0,
neighbour_averageForm: {
res_name: '',
kernel_size: null
},
neighbour_averageLoad: false,
median_filter_active: 0,
median_filterForm: {
res_name: '',
kernel_size: null
},
median_filterLoad: false,
ideal_filter_active: 0,
ideal_filterForm: {
res_name: '',
d0: null
},
ideal_filterLoad: false,
barte_filter_active: 0,
barte_filterForm: {
res_name: '',
d0: null,
rank: null
},
barte_filterLoad: false,
exp_filter_active: 0,
exp_filterForm: {
res_name: '',
d0: null,
rank: null
},
exp_filterLoad: false
}
},
components: {
Head,
Navigation,
Copyright,
PictureChooseOne
},
methods: {
cancel() {
this.selection = [];
this.displayImg = [{fileName: '../../../assets/picture/default_pic.jpg'}, {fileName: '../../../assets/picture/default_pic.jpg'}];
this.clear_active();
this.neighbour_averageForm.res_name = '';
this.neighbour_averageForm.kernel_size = null;
this.median_filterForm.res_name = '';
this.median_filterForm.kernel_size = null;
this.ideal_filterForm.res_name = '';
this.ideal_filterForm.d0 = null;
this.barte_filterForm.res_name = '';
this.barte_filterForm.d0 = null;
this.barte_filterForm.rank = null;
this.exp_filterForm.res_name = '';
this.exp_filterForm.d0 = null;
this.exp_filterForm.rank = null;
this.neighbour_averageLoad = false;
this.median_filterLoad = false;
this.ideal_filterLoad = false;
this.barte_filterLoad = false;
this.exp_filterLoad = false;
this.processResult = {
code: '',
message: '',
result_name: '../../../assets/picture/default_pic.jpg'
};
},
clear_active() {
this.neighbour_average_active = 0;
this.median_filter_active = 0;
this.ideal_filter_active = 0;
this.barte_filter_active = 0;
this.exp_filter_active = 0;
},
async neighbour_average_next() {
let tmp = this.neighbour_average_active;
this.clear_active();
this.neighbour_average_active = tmp;
if (this.neighbour_average_active === 0) {
this.selection = this.$refs["neighbour_averageSelection"].multipleSelection;
this.displayImg[0] = this.selection[0];
if (this.selection.length !== 1) {
this.$alert('选择的图片数量不是一张!', '数量错误', {
confirmButtonText: '确定'
});
return
}
} else if (this.neighbour_average_active === 1) {
if ((this.neighbour_averageForm.res_name === '') || (this.neighbour_averageForm.kernel_size === null)) {
this.$alert('输出图像名称不能为空!<br>核数不能为空!', '参数错误', {
confirmButtonText: '确定',
dangerouslyUseHTMLString: true
});
return
}
this.neighbour_averageForm.kernel_size = parseInt(this.neighbour_averageForm.kernel_size);
if (!this.utils.isInteger(this.neighbour_averageForm.kernel_size)) {
this.$alert('核数必须为数字!', '参数错误', {
confirmButtonText: '确定'
});
return
}
if ((this.neighbour_averageForm.kernel_size % 2 === 0) || (this.neighbour_averageForm.kernel_size <= 0)) {
this.$alert('核数必须为正奇数!', '参数错误', {
confirmButtonText: '确定'
});
return
}
this.neighbour_averageForm.res_name = this.utils.calculate_res_name(this.neighbour_averageForm.res_name);
} else if (this.neighbour_average_active === 2) {
const axios = require('axios')
this.neighbour_averageLoad = true;
await axios.get(
this.constant.data().BaseUrl + '/smooth_sharpen/smoo_neighbour_average', {
params: {
img_name: this.selection[0].fileName,
result_name: this.neighbour_averageForm.res_name,
kernel_size: this.neighbour_averageForm.kernel_size
}
}
).then(
(res) => {
this.processResult = res.data;
if (this.processResult.code === '1') {
this.$message({
message: '图片处理成功!',
type: 'success'
});
} else if (this.processResult.code === '2') {
this.$message.error('图片处理成功!');
}
}
)
this.neighbour_averageLoad = false;
} else if (this.neighbour_average_active === 3) {
this.neighbour_average_active = 0;
return
}
this.neighbour_average_active++;
},
async median_filter_next() {
let tmp = this.median_filter_active;
this.clear_active();
this.median_filter_active = tmp;
if (this.median_filter_active === 0) {
this.selection = this.$refs["median_filterSelection"].multipleSelection;
this.displayImg[0] = this.selection[0];
if (this.selection.length !== 1) {
this.$alert('选择的图片数量不是一张!', '数量错误', {
confirmButtonText: '确定'
});
return
}
} else if (this.median_filter_active === 1) {
if ((this.median_filterForm.res_name === '') || (this.median_filterForm.kernel_size === null)) {
this.$alert('输出图像名称不能为空!<br>核数不能为空!', '参数错误', {
confirmButtonText: '确定',
dangerouslyUseHTMLString: true
});
return
}
this.median_filterForm.kernel_size = parseInt(this.median_filterForm.kernel_size);
if (!this.utils.isInteger(this.median_filterForm.kernel_size)) {
this.$alert('核数必须为数字!', '参数错误', {
confirmButtonText: '确定'
});
return
}
if ((this.median_filterForm.kernel_size % 2 === 0) || (this.median_filterForm.kernel_size <= 0)) {
this.$alert('核数必须为正奇数!', '参数错误', {
confirmButtonText: '确定'
});
return
}
this.median_filterForm.res_name = this.utils.calculate_res_name(this.median_filterForm.res_name);
} else if (this.median_filter_active === 2) {
const axios = require('axios')
this.median_filterLoad = true;
await axios.get(
this.constant.data().BaseUrl + '/smooth_sharpen/smoo_median_filter', {
params: {
img_name: this.selection[0].fileName,
result_name: this.median_filterForm.res_name,
kernel_size: this.median_filterForm.kernel_size
}
}
).then(
(res) => {
this.processResult = res.data;
if (this.processResult.code === '1') {
this.$message({
message: '图片处理成功!',
type: 'success'
});
} else if (this.processResult.code === '2') {
this.$message.error('图片处理成功!');
}
}
)
this.median_filterLoad = false;
} else if (this.median_filter_active === 3) {
this.median_filter_active = 0;
return
}
this.median_filter_active++;
},
async ideal_filter_next() {
let tmp = this.ideal_filter_active;
this.clear_active();
this.ideal_filter_active = tmp;
if (this.ideal_filter_active === 0) {
this.selection = this.$refs["ideal_filterSelection"].multipleSelection;
this.displayImg[0] = this.selection[0];
if (this.selection.length !== 1) {
this.$alert('选择的图片数量不是一张!', '数量错误', {
confirmButtonText: '确定'
});
return
}
} else if (this.ideal_filter_active === 1) {
if ((this.ideal_filterForm.res_name === '') || (this.ideal_filterForm.d0 === null)) {
this.$alert('输出图像名称不能为空!<br>阈值不能为空!', '参数错误', {
confirmButtonText: '确定',
dangerouslyUseHTMLString: true
});
return
}
this.ideal_filterForm.d0 = parseInt(this.ideal_filterForm.d0);
if (!this.utils.isInteger(this.ideal_filterForm.d0)) {
this.$alert('阈值必须为数字!', '参数错误', {
confirmButtonText: '确定'
});
return
}
if ((this.ideal_filterForm.d0 < 0) || (this.ideal_filterForm.d0 > 255)) {
this.$alert('阈值必须在0255之间', '参数错误', {
confirmButtonText: '确定'
});
return
}
this.ideal_filterForm.res_name = this.utils.calculate_res_name(this.ideal_filterForm.res_name);
} else if (this.ideal_filter_active === 2) {
const axios = require('axios')
this.ideal_filterLoad = true;
await axios.get(
this.constant.data().BaseUrl + '/smooth_sharpen/smoo_ideal_filter', {
params: {
img_name: this.selection[0].fileName,
result_name: this.ideal_filterForm.res_name,
d0: this.ideal_filterForm.d0
}
}
).then(
(res) => {
this.processResult = res.data;
if (this.processResult.code === '1') {
this.$message({
message: '图片处理成功!',
type: 'success'
});
} else if (this.processResult.code === '2') {
this.$message.error('图片处理成功!');
}
}
)
this.ideal_filterLoad = false;
} else if (this.ideal_filter_active === 3) {
this.ideal_filter_active = 0;
return
}
this.ideal_filter_active++;
},
async barte_filter_next() {
let tmp = this.barte_filter_active;
this.clear_active();
this.barte_filter_active = tmp;
if (this.barte_filter_active === 0) {
this.selection = this.$refs["barte_filterSelection"].multipleSelection;
this.displayImg[0] = this.selection[0];
if (this.selection.length !== 1) {
this.$alert('选择的图片数量不是一张!', '数量错误', {
confirmButtonText: '确定'
});
return
}
} else if (this.barte_filter_active === 1) {
if ((this.barte_filterForm.res_name === '') || (this.barte_filterForm.d0 === null) || (this.barte_filterForm.rank === null)) {
this.$alert('输出图像名称不能为空!<br>阈值不能为空!<br>阶数不能为空!', '参数错误', {
confirmButtonText: '确定',
dangerouslyUseHTMLString: true
});
return
}
this.barte_filterForm.d0 = parseInt(this.barte_filterForm.d0);
this.barte_filterForm.rank = parseInt(this.barte_filterForm.rank);
if ((!this.utils.isInteger(this.barte_filterForm.d0)) || (!this.utils.isInteger(this.barte_filterForm.rank))) {
this.$alert('阈值必须为数字!<br>阶数必须为数字!', '参数错误', {
confirmButtonText: '确定',
dangerouslyUseHTMLString: true
});
return
}
if ((this.barte_filterForm.d0 < 0) || (this.barte_filterForm.d0 > 255)) {
this.$alert('阈值必须在0255之间', '参数错误', {
confirmButtonText: '确定'
});
return
}
this.barte_filterForm.res_name = this.utils.calculate_res_name(this.barte_filterForm.res_name);
} else if (this.barte_filter_active === 2) {
const axios = require('axios')
this.barte_filterLoad = true;
await axios.get(
this.constant.data().BaseUrl + '/smooth_sharpen/smoo_barte_filter', {
params: {
img_name: this.selection[0].fileName,
result_name: this.barte_filterForm.res_name,
d0: this.barte_filterForm.d0,
rank: this.barte_filterForm.rank
}
}
).then(
(res) => {
this.processResult = res.data;
if (this.processResult.code === '1') {
this.$message({
message: '图片处理成功!',
type: 'success'
});
} else if (this.processResult.code === '2') {
this.$message.error('图片处理成功!');
}
}
)
this.barte_filterLoad = false;
} else if (this.barte_filter_active === 3) {
this.barte_filter_active = 0;
return
}
this.barte_filter_active++;
},
async exp_filter_next() {
let tmp = this.exp_filter_active;
this.clear_active();
this.exp_filter_active = tmp;
if (this.exp_filter_active === 0) {
this.selection = this.$refs["exp_filterSelection"].multipleSelection;
this.displayImg[0] = this.selection[0];
if (this.selection.length !== 1) {
this.$alert('选择的图片数量不是一张!', '数量错误', {
confirmButtonText: '确定'
});
return
}
} else if (this.exp_filter_active === 1) {
if ((this.exp_filterForm.res_name === '') || (this.exp_filterForm.d0 === null) || (this.exp_filterForm.rank === null)) {
this.$alert('输出图像名称不能为空!<br>阈值不能为空!<br>阶数不能为空!', '参数错误', {
confirmButtonText: '确定',
dangerouslyUseHTMLString: true
});
return
}
this.exp_filterForm.d0 = parseInt(this.exp_filterForm.d0);
this.exp_filterForm.rank = parseInt(this.exp_filterForm.rank);
if ((!this.utils.isInteger(this.exp_filterForm.d0)) || (!this.utils.isInteger(this.exp_filterForm.rank))) {
this.$alert('阈值必须为数字!<br>阶数必须为数字!', '参数错误', {
confirmButtonText: '确定',
dangerouslyUseHTMLString: true
});
return
}
if ((this.exp_filterForm.d0 < 0) || (this.exp_filterForm.d0 > 255)) {
this.$alert('阈值必须在0255之间', '参数错误', {
confirmButtonText: '确定'
});
return
}
this.exp_filterForm.res_name = this.utils.calculate_res_name(this.exp_filterForm.res_name);
} else if (this.exp_filter_active === 2) {
const axios = require('axios')
this.exp_filterLoad = true;
await axios.get(
this.constant.data().BaseUrl + '/smooth_sharpen/smoo_exp_filter', {
params: {
img_name: this.selection[0].fileName,
result_name: this.exp_filterForm.res_name,
d0: this.exp_filterForm.d0,
rank: this.exp_filterForm.rank
}
}
).then(
(res) => {
this.processResult = res.data;
if (this.processResult.code === '1') {
this.$message({
message: '图片处理成功!',
type: 'success'
});
} else if (this.processResult.code === '2') {
this.$message.error('图片处理成功!');
}
}
)
this.exp_filterLoad = false;
} else if (this.exp_filter_active === 3) {
this.exp_filter_active = 0;
return
}
this.exp_filter_active++;
}
}
}
</script>
<style scoped>
</style>

@ -0,0 +1,275 @@
<template>
<div class="basic" style="background: #e9e9e9; min-height: 100%">
<el-head>
<Navigation/>
</el-head>
<el-container style="position: absolute; height: 100%; width: 100%; border: 0">
<el-container style="margin-top: 5%; margin-right: 300px; margin-left: 300px">
<el-header style="text-align: center; font-size: 36px">
<div class="heading">
{{ headmsg }}
</div>
</el-header>
<el-main style="text-align: left; font-size: 18px">
{{ intromsg }}
<el-tabs type="border-card" style="margin-top: 30px; min-height: 80%">
<el-tab-pane label="风格迁移">
<el-steps :active="gauss_noise_active" align-center finish-status="success"style="margin-top: 40px">
<el-step title="选择风格图片"></el-step>
<el-step title="选择内容图片"></el-step>
<el-step title="输入参数"></el-step>
<el-step title="处理图片"></el-step>
</el-steps>
<div v-show="gauss_noise_active === 0" style="margin-top: 20px;">
<PictureChooseOne ref="gauss_noiseSelection1"/>
</div>
<div v-show="gauss_noise_active === 1" style="margin-top: 20px;">
<PictureChooseOne ref="gauss_noiseSelection2"/>
</div>
<div v-show="gauss_noise_active === 2"
style="text-align: center; margin-top: 20px; min-height: 375px; max-height: 375px">
<div style="margin-left: 20%; margin-right: 20%">
<el-form :model="gauss_noiseForm" class="demo-form-inline">
<el-form-item label="输出图像名称"
label-width="30%"
:rules="[
{ required: true, message: '名称不能为空'}
]"
style="align-content: center; margin-left: 10%; margin-right: 10%; width: 60%">
<el-input v-model="gauss_noiseForm.res_name">
<template slot="append">.jpg</template>
</el-input>
</el-form-item>
<el-form-item label="训练epoch次数默认为1"
label-width="30%"
style="align-content: center; margin-left: 10%; margin-right: 10%; width: 60%">
<el-input v-model="gauss_noiseForm.epoch">
<template slot="append">.jpg</template>
</el-input>
</el-form-item>
<el-form-item label="每个epoch训练次数默认为100"
label-width="30%"
style="align-content: center; margin-left: 10%; margin-right: 10%; width: 60%">
<el-input v-model="gauss_noiseForm.per_epoch">
<template slot="append">.jpg</template>
</el-input>
</el-form-item>
<el-form-item label="学习率默认为0.03"
label-width="30%"
style="align-content: center; margin-left: 10%; margin-right: 10%; width: 60%">
<el-input v-model="gauss_noiseForm.learn_rate">
<template slot="append">.jpg</template>
</el-input>
</el-form-item>
</el-form>
</div>
</div>
<div v-show="gauss_noise_active === 3"
style="text-align: center; margin-top: 20px; min-height: 375px; max-height: 375px">
<div>
<span class="demonstration">原图片</span>
<br>
<img :src="this.displayImg[0].fileUrl" alt=""
style="width: auto; height: auto; max-width: 400px; max-height: 300px; margin-top: 30px">
</div>
</div>
<div v-show="gauss_noise_active === 4"
style="text-align: center; margin-top: 20px; min-height: 375px; max-height: 375px">
<div>
<span class="demonstration">结果图片</span>
<br>
<img :src="this.processResult.result_name" alt=""
style="width: auto; height: auto; max-width: 400px; max-height: 300px; margin-top: 30px">
</div>
</div>
<el-button style="margin-left: 70%; margin-top: 30px;" @click="cancel"></el-button>
<el-button v-show="gauss_noise_active <= 3" :loading="gauss_noiseLoad" style="margin-left: 10px; margin-top: 10px;"
@click="gauss_noise_next">下一步
</el-button>
<el-button v-show="gauss_noise_active >= 4" :loading="gauss_noiseLoad" style="margin-left: 10px; margin-top: 10px;"
@click="cancel">完成
</el-button>
</el-tab-pane>
</el-tabs>
</el-main>
<el-footer height="10px">
<Copyright/>
</el-footer>
</el-container>
</el-container>
</div>
</template>
<script>
import Navigation from "@/components/global/Navigation"
import Copyright from "@/components/global/Copyright"
import Head from "@/components/global/Head"
import PictureChooseOne from "@/components/global/PictureChooseOne"
export default {
name: "Style",
data() {
return {
headmsg: '图片风格迁移',
selection_style: [],
selection_content: [],
displayImg: [
{
fileName: '../../../assets/picture/default_pic.jpg'
},
{
fileName: '../../../assets/picture/default_pic.jpg'
}
],
processResult: {
code: '',
message: '',
result_name: '../../../assets/picture/default_pic.jpg'
},
gauss_noise_active: 0,
gauss_noiseForm: {
res_name: '',
epoch: 1,
per_epoch: 100,
learn_rate: 0.03
},
gauss_noiseLoad: false,
sault_pepper_noise_active: 0,
sault_pepper_noiseForm: {
res_name: '',
ran_x1: null,
ran_y1: null,
ran_x2: null,
ran_y2: null
},
sault_pepper_noiseLoad: false
}
},
components: {
Head,
Navigation,
Copyright,
PictureChooseOne
},
methods: {
cancel() {
this.selection_style = [];
this.selection_content = [];
this.displayImg = [{fileName: '../../../assets/picture/default_pic.jpg'}, {fileName: '../../../assets/picture/default_pic.jpg'}];
this.clear_active();
this.gauss_noiseForm.res_name = '';
this.sault_pepper_noiseForm.res_name = '';
this.sault_pepper_noiseForm.ran_x1 = null;
this.sault_pepper_noiseForm.ran_y1 = null;
this.sault_pepper_noiseForm.ran_x2 = null;
this.sault_pepper_noiseForm.ran_y2 = null;
this.gauss_noiseLoad = false;
this.sault_pepper_noiseLoad = false;
this.processResult = {
code: '',
message: '',
result_name: '../../../assets/picture/default_pic.jpg'
};
},
clear_active() {
this.gauss_noise_active = 0;
this.sault_pepper_noise_active = 0;
},
async gauss_noise_next() {
let tmp = this.gauss_noise_active;
this.clear_active();
this.gauss_noise_active = tmp;
if (this.gauss_noise_active === 0) {
this.selection_style = this.$refs["gauss_noiseSelection1"].multipleSelection;
this.displayImg[0] = this.selection_style[0];
if (this.selection_style.length !== 1) {
this.$alert('选择的图片数量不是一张!', '数量错误', {
confirmButtonText: '确定'
});
return
}
} else if (this.gauss_noise_active === 1) {
this.selection_content = this.$refs["gauss_noiseSelection2"].multipleSelection;
this.displayImg[0] = this.selection_content[0];
if (this.selection_content.length !== 1) {
this.$alert('选择的图片数量不是一张!', '数量错误', {
confirmButtonText: '确定'
});
return
}
} else if (this.gauss_noise_active === 2) {
if (this.gauss_noiseForm.res_name === '') {
this.$alert('输出图像名称不能为空!', '命名错误', {
confirmButtonText: '确定'
});
return
}
this.gauss_noiseForm.res_name = this.utils.calculate_res_name(this.gauss_noiseForm.res_name);
} else if (this.gauss_noise_active === 3) {
const axios = require('axios')
this.gauss_noiseLoad = true;
await axios.get(
this.constant.data().BaseUrl + '/styleTransfer/style_transfer', {
params: {
img_style_name: this.selection_style[0].fileName,
img_content_name: this.selection_content[0].fileName,
result_name: this.gauss_noiseForm.res_name,
epoch: this.gauss_noiseForm.epoch,
per_epoch: this.gauss_noiseForm.per_epoch,
learn_rate: this.gauss_noiseForm.learn_rate
}
}
).then(
(res) => {
this.processResult = res.data;
if (this.processResult.code === '1') {
this.$message({
message: '图片处理成功!',
type: 'success'
});
} else if (this.processResult.code === '2') {
this.$message.error('图片处理成功!');
}
}
)
this.gauss_noiseLoad = false;
} else if (this.gauss_noise_active === 3) {
this.gauss_noise_active = 0;
return
}
this.gauss_noise_active++;
},
}
}
</script>
<style scoped>
</style>

@ -0,0 +1,22 @@
import Vue from 'vue'
import App from './App.vue'
import ElementUI from 'element-ui'
import 'element-ui/lib/theme-chalk/index.css'
import router from './router'
import Constant from "@/assets/javascript/Constant"
import fileMaintain from "@/assets/javascript/fileMaintain"
import "@/assets/css/globalContainer.css"
import utils from "@/assets/javascript/utils"
Vue.config.productionTip = false
Vue.use(ElementUI)
Vue.prototype.constant = Constant
Vue.prototype.fileMaintain = fileMaintain.fileMethods
Vue.prototype.utils = utils.methods
new Vue({
el: '#app',
router,
render: h => h(App),
}).$mount('#app')

@ -0,0 +1,72 @@
import Vue from 'vue'
import Router from 'vue-router'
import Home from "@/components/Home"
import BasicFunc from "@/components/pages/BasicFunc"
import Histogram from "@/components/pages/Histogram"
import Segmentation from "@/components/pages/Segmentation"
import Smooth from "@/components/pages/Smooth"
import Sharpen from "@/components/pages/Sharpen"
import Morphological from "@/components/pages/Morphological"
import Noise from "@/components/pages/Noise"
import Repair from "@/components/pages/Repair"
import Style from "@/components/pages/StyleTransfer"
Vue.use(Router)
export default new Router({
routes: [
{
path: '/',
name: 'Home',
component: Home
},
{
path: '/basic_func',
name: 'BasicFunc',
component: BasicFunc
},
{
path: '/histogram',
name: 'Histogram',
component: Histogram
},
{
path: '/segmentation',
name: 'Segmentation',
component: Segmentation
}
,
{
path: '/smooth_sharpen/smooth',
name: 'Smooth',
component: Smooth
}
,
{
path: '/smooth_sharpen/sharpen',
name: 'Sharpen',
component: Sharpen
},
{
path: '/morphological',
name: 'Morphological',
component: Morphological
},
{
path: '/fix/noise',
name: 'Noise',
component: Noise
},
{
path: '/fix/repair',
name: 'Repair',
component: Repair
},
{
path: '/style_transfer',
name: 'Style',
component: Style
}
]
})

@ -0,0 +1,12 @@
module.exports = {
publicPath: './',
devServer: {
disableHostCheck: false,
host: "127.0.0.1",
port: 9091,
https: false,
hotOnly: false,
proxy: null
},
lintOnSave: false
};
Loading…
Cancel
Save