Spaces:
Running
Running
Update app.py
Browse files
app.py
CHANGED
@@ -778,7 +778,39 @@ async def create_mask_sum(image: UploadFile = File(...), risk_level: int = Form(
|
|
778 |
|
779 |
return FileResponse(output_path)
|
780 |
|
781 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
782 |
|
783 |
@app.get("/", response_class=HTMLResponse)
|
784 |
async def read_root():
|
@@ -807,16 +839,15 @@ async def read_root():
|
|
807 |
.form-control-file { font-size: 1rem; }
|
808 |
.form-group { margin-bottom: 25px; }
|
809 |
.btn-success { padding: 10px 20px; border-radius: 50px; }
|
810 |
-
#loadingSpinner {
|
811 |
-
|
812 |
-
|
813 |
-
|
814 |
-
|
815 |
-
|
816 |
-
|
817 |
-
|
818 |
-
}
|
819 |
-
|
820 |
</style>
|
821 |
</head>
|
822 |
<body>
|
@@ -824,7 +855,6 @@ async def read_root():
|
|
824 |
<i class="fas fa-spinner fa-spin fa-3x"></i>
|
825 |
<p>画像を処理中です。少々お待ちください...</p>
|
826 |
</div>
|
827 |
-
|
828 |
<div class="container">
|
829 |
<h1><i class="fas fa-image"></i> 画像処理アプリ - モザイクとインペイント</h1>
|
830 |
<div class="form-group">
|
@@ -854,7 +884,7 @@ async def read_root():
|
|
854 |
<script src="https://code.jquery.com/jquery-3.5.1.min.js"></script>
|
855 |
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/js/bootstrap.min.js"></script>
|
856 |
<script src="https://code.jquery.com/ui/1.12.1/jquery-ui.js"></script>
|
857 |
-
|
858 |
$(function() {
|
859 |
$("#slider").slider({
|
860 |
range: "min",
|
@@ -915,8 +945,10 @@ async def read_root():
|
|
915 |
alert("画像を選択して縮小してください。");
|
916 |
return;
|
917 |
}
|
|
|
|
|
918 |
const formData = new FormData();
|
919 |
-
formData.append('image', resizedImageBlob, 'resized_image.jpg');
|
920 |
formData.append('risk_level', riskLevel);
|
921 |
let apiEndpoint;
|
922 |
if (processingType === "opencv") {
|
@@ -948,64 +980,16 @@ async def read_root():
|
|
948 |
.catch(error => {
|
949 |
console.error("画像処理に失敗しました。", error);
|
950 |
alert("画像処理に失敗しました。");
|
|
|
|
|
|
|
|
|
951 |
});
|
952 |
}
|
953 |
-
|
954 |
-
const processingType = document.getElementById('processingType').value;
|
955 |
-
const riskLevel = $("#slider").slider("value");
|
956 |
-
const resultDiv = document.getElementById('result');
|
957 |
-
const processedImage = document.getElementById('processedImage');
|
958 |
-
const downloadLink = document.getElementById('downloadLink');
|
959 |
-
if (!resizedImageBlob) {
|
960 |
-
alert("画像を選択して縮小してください。");
|
961 |
-
return;
|
962 |
-
}
|
963 |
-
// ローディングスピナーを表示
|
964 |
-
document.getElementById('loadingSpinner').style.display = 'block';
|
965 |
-
|
966 |
-
const formData = new FormData();
|
967 |
-
formData.append('image', resizedImageBlob, 'resized_image.jpg');
|
968 |
-
formData.append('risk_level', riskLevel);
|
969 |
-
let apiEndpoint;
|
970 |
-
if (processingType === "opencv") {
|
971 |
-
apiEndpoint = "/create-mask-and-inpaint-opencv";
|
972 |
-
} else if (processingType === "simple_lama") {
|
973 |
-
apiEndpoint = "/create-mask-and-inpaint-simple-lama";
|
974 |
-
} else if (processingType === "stamp") {
|
975 |
-
apiEndpoint = "/create-mask-and-inpaint-stamp";
|
976 |
-
} else if (processingType == "mosaic") {
|
977 |
-
apiEndpoint = "/create-mask-and-inpaint-mosaic";
|
978 |
-
}
|
979 |
-
const url = "https://rein0421-aidentify.hf.space" + apiEndpoint;
|
980 |
-
fetch(url, {
|
981 |
-
method: 'POST',
|
982 |
-
body: formData
|
983 |
-
})
|
984 |
-
.then(response => {
|
985 |
-
if (!response.ok) {
|
986 |
-
throw new Error("Network response was not ok");
|
987 |
-
}
|
988 |
-
return response.blob();
|
989 |
-
})
|
990 |
-
.then(blob => {
|
991 |
-
const objectURL = URL.createObjectURL(blob);
|
992 |
-
processedImage.src = objectURL;
|
993 |
-
downloadLink.href = objectURL;
|
994 |
-
resultDiv.style.display = "block";
|
995 |
-
})
|
996 |
-
.catch(error => {
|
997 |
-
console.error("画像処理に失敗しました。", error);
|
998 |
-
alert("画像処理に失敗しました。");
|
999 |
-
})
|
1000 |
-
.finally(() => {
|
1001 |
-
// ローディングスピナーを非表示にする
|
1002 |
-
document.getElementById('loadingSpinner').style.display = 'none';
|
1003 |
-
});
|
1004 |
-
}
|
1005 |
-
|
1006 |
-
</script>
|
1007 |
</body>
|
1008 |
</html>
|
|
|
1009 |
"""
|
1010 |
return HTMLResponse(content=html_content)
|
1011 |
if __name__ == "__main__":
|
|
|
778 |
|
779 |
return FileResponse(output_path)
|
780 |
|
781 |
+
# カスケードファイルの読み込み (顔検出)
|
782 |
+
face_cascade = cv2.CascadeClassifier(cv2.data.haarcascades + 'haarcascade_frontalface_default.xml')
|
783 |
+
|
784 |
+
def apply_mosaic(image, x, y, w, h, mosaic_level=15):
|
785 |
+
""" 指定範囲にモザイク処理を適用 """
|
786 |
+
face = image[y:y+h, x:x+w]
|
787 |
+
face = cv2.resize(face, (w // mosaic_level, h // mosaic_level))
|
788 |
+
face = cv2.resize(face, (w, h), interpolation=cv2.INTER_NEAREST)
|
789 |
+
image[y:y+h, x:x+w] = face
|
790 |
+
return image
|
791 |
+
|
792 |
+
@app.post("/mosaic_face")
|
793 |
+
async def mosaic_face(file: UploadFile = File(...)):
|
794 |
+
# 画像ファイルを読み込み
|
795 |
+
image_data = await file.read()
|
796 |
+
np_array = np.frombuffer(image_data, np.uint8)
|
797 |
+
img = cv2.imdecode(np_array, cv2.IMREAD_COLOR)
|
798 |
+
|
799 |
+
# グレースケール変換と顔検出
|
800 |
+
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
|
801 |
+
faces = face_cascade.detectMultiScale(gray, scaleFactor=1.1, minNeighbors=4, minSize=(30, 30))
|
802 |
+
|
803 |
+
# 検出した顔にモザイクを適用
|
804 |
+
for (x, y, w, h) in faces:
|
805 |
+
img = apply_mosaic(img, x, y, w, h)
|
806 |
+
|
807 |
+
# 一時ファイルに保存
|
808 |
+
with tempfile.NamedTemporaryFile(delete=False, suffix=".jpg") as temp_file:
|
809 |
+
temp_file_path = Path(temp_file.name)
|
810 |
+
cv2.imwrite(str(temp_file_path), img)
|
811 |
+
|
812 |
+
# 一時ファイルをレスポンスとして返す
|
813 |
+
return FileResponse(path=temp_file_path, media_type="image/jpeg", filename="mosaic_image.jpg")
|
814 |
|
815 |
@app.get("/", response_class=HTMLResponse)
|
816 |
async def read_root():
|
|
|
839 |
.form-control-file { font-size: 1rem; }
|
840 |
.form-group { margin-bottom: 25px; }
|
841 |
.btn-success { padding: 10px 20px; border-radius: 50px; }
|
842 |
+
#loadingSpinner {
|
843 |
+
position: fixed;
|
844 |
+
top: 50%;
|
845 |
+
left: 50%;
|
846 |
+
transform: translate(-50%, -50%);
|
847 |
+
color: #007bff;
|
848 |
+
text-align: center;
|
849 |
+
z-index: 9999;
|
850 |
+
}
|
|
|
851 |
</style>
|
852 |
</head>
|
853 |
<body>
|
|
|
855 |
<i class="fas fa-spinner fa-spin fa-3x"></i>
|
856 |
<p>画像を処理中です。少々お待ちください...</p>
|
857 |
</div>
|
|
|
858 |
<div class="container">
|
859 |
<h1><i class="fas fa-image"></i> 画像処理アプリ - モザイクとインペイント</h1>
|
860 |
<div class="form-group">
|
|
|
884 |
<script src="https://code.jquery.com/jquery-3.5.1.min.js"></script>
|
885 |
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/js/bootstrap.min.js"></script>
|
886 |
<script src="https://code.jquery.com/ui/1.12.1/jquery-ui.js"></script>
|
887 |
+
<script>
|
888 |
$(function() {
|
889 |
$("#slider").slider({
|
890 |
range: "min",
|
|
|
945 |
alert("画像を選択して縮小してください。");
|
946 |
return;
|
947 |
}
|
948 |
+
// ローディングスピナーを表示
|
949 |
+
document.getElementById('loadingSpinner').style.display = 'block';
|
950 |
const formData = new FormData();
|
951 |
+
formData.append('image', resizedImageBlob, 'resized_image.jpg');
|
952 |
formData.append('risk_level', riskLevel);
|
953 |
let apiEndpoint;
|
954 |
if (processingType === "opencv") {
|
|
|
980 |
.catch(error => {
|
981 |
console.error("画像処理に失敗しました。", error);
|
982 |
alert("画像処理に失敗しました。");
|
983 |
+
})
|
984 |
+
.finally(() => {
|
985 |
+
// ローディングスピナーを非表示にする
|
986 |
+
document.getElementById('loadingSpinner').style.display = 'none';
|
987 |
});
|
988 |
}
|
989 |
+
</script>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
990 |
</body>
|
991 |
</html>
|
992 |
+
|
993 |
"""
|
994 |
return HTMLResponse(content=html_content)
|
995 |
if __name__ == "__main__":
|