feat(v1): add basic backend and frontend
This commit is contained in:
61
backend/processing/tests/test_algorithms.py
Normal file
61
backend/processing/tests/test_algorithms.py
Normal file
@@ -0,0 +1,61 @@
|
||||
import numpy as np
|
||||
from django.test import SimpleTestCase
|
||||
|
||||
from processing.algorithms import (
|
||||
LAPLACIAN_MASK,
|
||||
ProcessingError,
|
||||
average_images,
|
||||
gamma,
|
||||
histogram_equalization,
|
||||
median_filter,
|
||||
negative,
|
||||
roberts,
|
||||
sobel,
|
||||
subtract_images,
|
||||
verify_registration,
|
||||
)
|
||||
|
||||
|
||||
class AlgorithmTests(SimpleTestCase):
|
||||
def test_negative_transform_uses_l_minus_one(self):
|
||||
image = np.array([[[0, 127, 255]]], dtype=np.uint8)
|
||||
result = negative(image, {})
|
||||
np.testing.assert_array_equal(result, np.array([[[255, 128, 0]]], dtype=np.uint8))
|
||||
|
||||
def test_gamma_identity(self):
|
||||
image = np.array([[[0, 128, 255]]], dtype=np.uint8)
|
||||
result = gamma(image, {"gamma": 1, "c": 1})
|
||||
np.testing.assert_array_equal(result, image)
|
||||
|
||||
def test_laplacian_mask_sums_to_zero(self):
|
||||
self.assertEqual(int(LAPLACIAN_MASK.sum()), 0)
|
||||
|
||||
def test_histogram_equalization_spreads_two_levels(self):
|
||||
image = np.array([[0, 0], [255, 255]], dtype=np.uint8)
|
||||
result = histogram_equalization(image, {})
|
||||
expected = np.dstack([image, image, image])
|
||||
np.testing.assert_array_equal(result, expected)
|
||||
|
||||
def test_median_removes_impulse_noise(self):
|
||||
image = np.full((3, 3, 3), 100, dtype=np.uint8)
|
||||
image[1, 1] = 255
|
||||
result = median_filter(image, {"size": 3})
|
||||
self.assertEqual(int(result[1, 1, 0]), 100)
|
||||
|
||||
def test_gradient_outputs_are_display_normalized(self):
|
||||
image = np.zeros((5, 5, 3), dtype=np.uint8)
|
||||
image[:, 3:] = 255
|
||||
self.assertEqual(sobel(image, {}).dtype, np.uint8)
|
||||
self.assertEqual(roberts(image, {}).dtype, np.uint8)
|
||||
|
||||
def test_arithmetic_requires_registered_shapes(self):
|
||||
left = np.zeros((2, 2, 3), dtype=np.uint8)
|
||||
right = np.zeros((3, 2, 3), dtype=np.uint8)
|
||||
with self.assertRaises(ProcessingError):
|
||||
verify_registration([left, right])
|
||||
|
||||
def test_average_and_subtraction(self):
|
||||
left = np.zeros((2, 2, 3), dtype=np.uint8)
|
||||
right = np.full((2, 2, 3), 100, dtype=np.uint8)
|
||||
self.assertEqual(int(average_images([left, right])[0, 0, 0]), 50)
|
||||
self.assertEqual(int(subtract_images(left, right)[0, 0, 0]), 0)
|
||||
64
backend/processing/tests/test_api.py
Normal file
64
backend/processing/tests/test_api.py
Normal file
@@ -0,0 +1,64 @@
|
||||
import tempfile
|
||||
from io import BytesIO
|
||||
from pathlib import Path
|
||||
from unittest.mock import patch
|
||||
|
||||
from django.core.files.uploadedfile import SimpleUploadedFile
|
||||
from django.test import TestCase, override_settings
|
||||
from PIL import Image
|
||||
from rest_framework.test import APIClient
|
||||
|
||||
|
||||
def png_upload(color=(32, 64, 128), size=(4, 4), name="sample.png"):
|
||||
buffer = BytesIO()
|
||||
Image.new("RGB", size, color).save(buffer, format="PNG")
|
||||
return SimpleUploadedFile(name, buffer.getvalue(), content_type="image/png")
|
||||
|
||||
|
||||
class ApiTests(TestCase):
|
||||
def setUp(self):
|
||||
self.tmp = tempfile.TemporaryDirectory()
|
||||
self.override = override_settings(MEDIA_ROOT=Path(self.tmp.name), IMAGE_SESSION_TTL_HOURS=1)
|
||||
self.override.enable()
|
||||
self.client = APIClient()
|
||||
|
||||
def tearDown(self):
|
||||
self.override.disable()
|
||||
self.tmp.cleanup()
|
||||
|
||||
def test_upload_and_process(self):
|
||||
upload = self.client.post("/api/images/", {"image": png_upload()}, format="multipart")
|
||||
self.assertEqual(upload.status_code, 201)
|
||||
session_id = upload.data["session_id"]
|
||||
self.assertEqual(len(upload.data["original_histogram"]), 256)
|
||||
|
||||
processed = self.client.post(
|
||||
"/api/process/",
|
||||
{"session_id": session_id, "operation": "gamma", "params": {"gamma": 1, "c": 1}},
|
||||
format="json",
|
||||
)
|
||||
self.assertEqual(processed.status_code, 200)
|
||||
self.assertEqual(len(processed.data["processed_histogram"]), 256)
|
||||
self.assertTrue(processed.data["image_data"].startswith("data:image/png;base64,"))
|
||||
|
||||
def test_invalid_kernel_rejected(self):
|
||||
upload = self.client.post("/api/images/", {"image": png_upload()}, format="multipart")
|
||||
processed = self.client.post(
|
||||
"/api/process/",
|
||||
{"session_id": upload.data["session_id"], "operation": "median_filter", "params": {"size": 4}},
|
||||
format="json",
|
||||
)
|
||||
self.assertEqual(processed.status_code, 400)
|
||||
|
||||
@patch("processing.services.run_batch_job.delay")
|
||||
def test_batch_returns_job_id(self, delay):
|
||||
first = self.client.post("/api/images/", {"image": png_upload(name="a.png")}, format="multipart")
|
||||
second = self.client.post("/api/images/", {"image": png_upload(color=(96, 96, 96), name="b.png")}, format="multipart")
|
||||
response = self.client.post(
|
||||
"/api/batch/",
|
||||
{"operation": "average", "session_ids": [first.data["session_id"], second.data["session_id"]]},
|
||||
format="json",
|
||||
)
|
||||
self.assertEqual(response.status_code, 202)
|
||||
self.assertIn("job_id", response.data)
|
||||
delay.assert_called_once()
|
||||
Reference in New Issue
Block a user