File size: 3,921 Bytes
465be14
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
from fastapi import FastAPI, File, UploadFile
from fastapi.responses import FileResponse, HTMLResponse
import cv2
import numpy as np
from rembg import remove
from PIL import Image
import io
import zipfile
import os

app = FastAPI()

# دالة لتحسين حدة الصورة (Sharpening) للحفاظ على جودة البكسل
def sharpen_image(image_cv):
    kernel = np.array([[0, -1, 0], 
                       [-1, 5,-1], 
                       [0, -1, 0]])
    return cv2.filter2D(image_cv, -1, kernel)

@app.get("/")
async def main():
    # واجهة مستخدم بسيطة جداً لرفع الصور
    content = """
    <html>
        <body style="font-family: Arial; text-align: center; margin-top: 50px;">
            <h2>أداة استخراج وتقطيع الفريمات (Sprite Extractor)</h2>
            <form action="/process-image/" enctype="multipart/form-data" method="post">
                <input name="file" type="file" accept="image/*">
                <input type="submit" value="معالجة وتحميل ZIP">
            </form>
        </body>
    </html>
    """
    return HTMLResponse(content=content)

@app.post("/process-image/")
async def process_image(file: UploadFile = File(...)):
    # 1. قراءة الصورة المرفوعة
    contents = await file.read()
    input_image = Image.open(io.BytesIO(contents)).convert("RGBA")
    
    # 2. إزالة الخلفية باستخدام الذكاء الاصطناعي (Rembg)
    output_image = remove(input_image)
    
    # تحويل الصورة إلى مصفوفة (Array) لكي يفهمها OpenCV
    open_cv_image = np.array(output_image)
    
    # 3. تحسين حدة الصورة (حتى لا تكون ضبابية)
    open_cv_image = sharpen_image(open_cv_image)

    # 4. تحويل الصورة إلى الأبيض والأسود لاكتشاف الأشكال (الفريمات)
    # نأخذ قناة الشفافية (Alpha Channel) لأننا أزلنا الخلفية
    alpha_channel = open_cv_image[:, :, 3]
    _, thresh = cv2.threshold(alpha_channel, 10, 255, cv2.THRESH_BINARY)
    
    # 5. البحث عن الفريمات (Contours)
    contours, _ = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
    
    # ترتيب الفريمات من اليسار إلى اليمين (حتى تكون الأنيميشن مرتبة)
    boundingBoxes = [cv2.boundingRect(c) for c in contours]
    (contours, boundingBoxes) = zip(*sorted(zip(contours, boundingBoxes), key=lambda b: b[1][0]))

    # تجهيز ملف الـ ZIP
    zip_filename = "/code/temp/sprites.zip"
    with zipfile.ZipFile(zip_filename, 'w') as zipf:
        frame_number = 1
        for contour in contours:
            # 6. الحصول على أبعاد كل فريم بدون الفراغ حوله
            x, y, w, h = cv2.boundingRect(contour)
            
            # تجاهل النقاط الصغيرة جداً (التي قد تكون أخطاء بكسل)
            if w > 5 and h > 5:
                # قص الفريم
                cropped_img = open_cv_image[y:y+h, x:x+w]
                
                # تحويله إلى صورة PIL للحفظ
                pil_img = Image.fromarray(cropped_img)
                
                # حفظ الفريم مؤقتاً
                frame_name = f"frame_{frame_number}.png"
                temp_path = f"/code/temp/{frame_name}"
                pil_img.save(temp_path, "PNG")
                
                # إضافته إلى ملف ZIP
                zipf.write(temp_path, arcname=frame_name)
                
                # حذف الملف المؤقت لتوفير المساحة
                os.remove(temp_path)
                frame_number += 1

    # 7. إرسال ملف ZIP للمستخدم
    return FileResponse(path=zip_filename, filename="sprites_ready.zip", media_type='application/zip')