DIP Using Flask
目的
制作一个简单的图像处理软件,能够实现基本的图像处理操作。
DIP
真正核心的图像处理部分是调库的,python在这方面充分展现了第三方库的强大功能。
requirements如下
import numpy as np
import cv2
from PIL import Image,ImageEnhance,ImageDraw,ImageFont
from skimage import io,color,transform,img_as_float,img_as_ubyte,img_as_uint
from skimage.exposure import histogram,adjust_gamma,adjust_log,adjust_sigmoid,equalize_hist
import matplotlib.pyplot as plt
GUI
在这个项目中,我的主要工作就是GUI,所以可谈的就比较多了。作为我的第一个独立创作的flask
应用,比较上心。
$ tree
├─.vscode
├─static
│ ├─css
│ ├─Image
│ └─js
├─templates
└─__pycache__
templates下是html的模板。对于flask
来说,需要渲染的模板通过render_templates
调用,这样可以极大的减少前端代码的重复率,提高开发效率。
对于这个项目来说,base.html
下有3个扩展,index.html
、basic.html
和dip.html
。这三个页面都继承自base.html
。
app.py
如下:
from flask import Flask, render_template, url_for, request, flash, redirect
from flask_bootstrap import Bootstrap
from forms import *
import os
from werkzeug.utils import secure_filename
from ImageOP import ImageProcess
import numpy as np
import pyperclip
app = Flask(__name__)
basedir = os.path.abspath(os.path.dirname(__file__))
bootstrap = Bootstrap(app)
app.config["SECRET_KEY"] = "A-VERY-LONG-SECRET-KEY"
filename = ""
iop = ImageProcess()
@app.route("/", methods=["POST", "GET"])
def index():
form = UpLoadFileForm()
global filename
print("in index")
if form.validate_on_submit():
f = form.photo.data
filename = os.path.join('static/Image', secure_filename(f.filename))
f.save(os.path.join(
basedir, filename
))
print(filename)
try:
iop.PhotoOpen(filename, change=True)
flash("上传成功: " + filename, category="success")
# return redirect(url_for('index'))
except Exception as e:
flash("文件打开失败", category="danger")
flash(e, category="danger")
if filename == "":
flash("请打开图片", category="warning")
if filename:
iop.PhotoOpen(filename)
print("index filename", filename)
return render_template("index.html", upload_file_form=form, filename=filename + "?randomstr=" + str(np.random.rand()))
@app.route("/basic", methods=["POST", "GET"])
def basic():
global filename
if filename == "":
return redirect(url_for("index"))
rotate_form = RotateForm()
if rotate_form.validate_on_submit():
filename = iop.RotateOP(rotate_form.angle.data)
if filename:
iop.PhotoOpen(filename)
return render_template("basic.html", filename=filename + "?randomstr=" + str(np.random.rand()), rotate_form=rotate_form)
@app.route("/dip", methods=["POST", "GET"])
def dip():
global filename
if filename == "":
return redirect(url_for("index"))
sharpen_form = SharpenForm()
if sharpen_form.validate_on_submit():
if sharpen_form.operation.data == 0:
filename = iop.BSCenhance(sharp_factor=sharpen_form.factor.data, choice="sharp")
elif sharpen_form.operation.data == 1:
filename = iop.BSCenhance(bright_factor=sharpen_form.factor.data, choice="contrast")
else:
filename = iop.BSCenhance(contrast_factor=sharpen_form.factor.data, choice="bright")
filter_form = FilterForm()
if filter_form.validate_on_submit():
# filter_form.filtername.data
arr = ["gaussian", "emboss", "edge", "sharp", "rect"]
filename = iop.filters(arr[filter_form.filtername.data])
linear_form = LinearForm()
if linear_form.validate_on_submit():
filename = iop.Hist_linear(a=linear_form.slope.data, b=linear_form.bias.data)
unlinear_form = UnLinearForm()
if unlinear_form.validate_on_submit():
if unlinear_form.function.data == 0:
filename = iop.Hist_gamma(1.2)
elif unlinear_form.function.data == 1:
filename = iop.Hist_sigmoid()
else:
filename = iop.Hist_log()
color_space_reverse_form = ColorSpaceReverseForm()
if color_space_reverse_form.validate_on_submit():
arr = ['RGB', 'HSV', 'RGB CIE', 'XYZ', 'YUV', 'YIQ', 'YPbPr', 'YCbCr']
filename = iop.ColorSpaceChange(arr[color_space_reverse_form.toSpace.data])
if filename:
iop.PhotoOpen(filename)
return render_template("dip.html", filename=filename + "?randomstr=" + str(np.random.rand()),
sharpen_form=sharpen_form, filter_form=filter_form,
linear_form=linear_form, unlinear_form=unlinear_form,
color_space_reverse_form=color_space_reverse_form)
@app.route("/share", methods=["POST", "GET"])
def share():
global filename
url = "127.0.0.1:5000/" + filename
pyperclip.copy(url)
flash("图片已经黏贴到剪切板", category="success")
return "filename: " + url
@app.route("/equalization", methods=["POST", "GET"])
def equalization():
global filename
filename = iop.Hist_equalize()
return redirect(url_for("dip"))
@app.route("/smooth", methods=["POST", "GET"])
def smooth():
global filename
filename = iop.filters("rect")
return "smooth over py"
@app.route("/histogram", methods=['POST', 'GET'])
def histogram():
print("in histogram")
hist = iop.Hist()
return hist + "?randomstr=" + str(np.random.rand())
@app.route("/FFTDCT", methods=["POST", "GET"])
def FFTDCT():
print("in fft dct", request.form.get("operation"))
ret = iop.FftDct(request.form.get("operation"))
print(ret)
return ret + "?randomstr=" + str(np.random.rand())
@app.route("/org", methods=["GET"])
def org():
global filename
print(filename)
filename = iop.orgFile
print(filename)
iop.PhotoOpen(filename, change=True)
return redirect(url_for("index"))
@app.route("/undo", methods=["GET", "POST"])
def undo():
global filename
print(iop.temp)
if iop.temp <= 1:
print("here")
filename = iop.orgFile
iop.PhotoOpen(iop.orgFile)
flash("已是最原始操作!", category="warning")
else:
iop.temp -= 1
filename = iop.base_dir + 'temp'+str(iop.temp)+'.'+iop.format
print("in undo")
print(filename)
iop.PhotoOpen(filename)
return "undo over py"
@app.route("/redo", methods=["GET", "POST"])
def redo():
try:
global filename
iop.temp += 1
iop.PhotoOpen(iop.base_dir + 'temp'+str(iop.temp)+'.'+iop.format)
filename = iop.base_dir + 'temp'+str(iop.temp)+'.'+iop.format
except:
iop.temp -= 1
flash("已经是最新操作!", category="warning")
return "redo over py"
@app.route("/rotate1")
def rotate1():
global filename
filename = iop.RotateOP(90)
return redirect(url_for("basic"))
@app.route("/rotate2")
def rotate2():
global filename
filename = iop.RotateOP(-90)
return redirect(url_for("basic"))
if __name__ == "__main__":
app.run(debug=True, host="0.0.0.0", port="5000")
flask
在flask中,有一个常用的语句@app.route()
,这个方法可以将重定向的网页调用下面的函数,这样就为html间的通信提供了有力的工具。
在javascript中,可以使用$ajax(settings)
来对python进行访问。
$ajax({
url: "127.0.0.1:5000/",
type: "POST",
data: {data: none},
dataType: html,
success: function(data, status) {
console.log(status);
}
});
在python中,使用flask提供的url_for
。
@app.route("/about")
def about():
return url_for("index")
总结
学习flask,让我了解了不少前端知识,我也第一次明白什么是框架,为什么要用框架。
之前曾用纯粹的javascript作为控制,尝试过一个“别踩白块”的实验,后来自己写了一个简单的俄罗斯方块。虽说使用同一种语言既控制前端又控制逻辑,应该是比较方便的,但是我在写方块的旋转和移动的时候,明显觉得对javascript的不适,感觉它不像python、PHP那样,想如果能用其他面向对象的Language来写更复杂的算法就好了。
事实上,python用户如此庞大,必然有与js交流的方法。
- flask是python的前端框架,引入flask极大简化了applications of python的开发周期。我曾经很不理解为什么要用框架,直接写不是更灵活么?大二的时候,曾经参与tjy基金会网站的项目,只学过一点MySQL的我就去搞数据库了,负责前端开发的java学长在做完前端之后还来帮SQL实战不来的我们,我就很佩服,那是第一次体会到用框架的方便和高效。
- flask能够模板化
Bootstrap3
,相比以前暴力撸html,Bootstrap
提供了更加美观、强大、功能完善和安全的界面,而且不会牺牲灵活性。 - flask对数据库也是很友好的。这学期有一个课程项目,要求用Unity3D制作一个甲烷气体浓度检测仪的使用教程,其中用来临时存储气体浓度数据都是放在
.txt
里,包括所有以前的课程项目,都是用临时的文本存储,现在想想感觉自己弱爆了…… - 所有的逻辑都在python内部进行啦!机器学习的模型在flask里面被调用就完了,很省事嘛!