-
Notifications
You must be signed in to change notification settings - Fork 60
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge branch 'master' into kainov-oleg-lab1
# Please enter a commit message to explain why this merge is necessary, # especially if it merges an updated upstream into a topic branch. # # Lines starting with '#' will be ignored, and an empty message aborts # the commit.
- Loading branch information
Showing
7 changed files
with
384 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
# Перевод из одного цветового пространства в другое (RGB, HSV, LAB) | ||
|
||
Выполнилa: | ||
|
||
- Ханова Татьяна | ||
- ННГУ, ИИТММ, каф. МОСТ, группа M0823-1 | ||
|
||
## Задание | ||
|
||
Реализовать класс конвертер, который должен предоставлять возможность перевода из одного цветового пространства в другое. Требуется поддержка следующих цветовых пространств: | ||
|
||
- RGB | ||
- HSV | ||
- LAB | ||
|
||
Класс должен позволять работать с заданным цветом в одном из цветовых пространств | ||
|
||
Все необходимые математические сведения по цветовым пространствам можно найти в статьях | ||
["HSV"][HSV], ["RGB"][RGB], ["LAB"][LAB] на сайте Wikipedia. Были использованы формулы для перевода и нормировки значений аналогичные [OpenCV][doc]. | ||
|
||
## Документация разработчика | ||
|
||
TBD | ||
|
||
<!-- LINKS --> | ||
|
||
[HSV]: https://en.wikipedia.org/wiki/HSL_and_HSV | ||
[RGB]: https://en.wikipedia.org/wiki/RGB_color_model | ||
[LAB]: https://en.wikipedia.org/wiki/Lab_color_space | ||
[doc]: http://docs.opencv.org/2.4.11/modules/imgproc/doc/miscellaneous_transformations.html#cvtcolor | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
import numpy as np | ||
from color_space import ColorSpace | ||
|
||
|
||
class InvalidColorError(Exception): | ||
pass | ||
|
||
|
||
class Color: | ||
COLOR_DIM = 3 | ||
|
||
value = np.zeros(COLOR_DIM, np.uint8) | ||
space = ColorSpace() | ||
|
||
def __init__(self, space=ColorSpace(), value=np.zeros(3, np.uint8)): | ||
if value.size != self.COLOR_DIM: | ||
raise InvalidColorError('invalid color size') | ||
|
||
if value[value < 0].size != 0 or value[value > 255].size != 0: | ||
raise InvalidColorError('invalid color values') | ||
|
||
self.space = space | ||
self.value = value | ||
|
||
def __str__(self): | ||
return "{} {}".format(self.space, self.value.tolist()) | ||
|
||
def __eq__(self, other_color): | ||
eq_space = self.space == other_color.space | ||
eq_value = np.array_equal(self.value, other_color.value) | ||
return eq_space and eq_value |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
class InvalidColorSpace(Exception): | ||
pass | ||
|
||
|
||
class ColorSpace: | ||
SUPPORTED_COLOR_SPACES = ["RGB", "HSV", "LAB"] | ||
|
||
color_space = "RGB" | ||
|
||
def __init__(self, color_space="RGB"): | ||
if color_space not in self.SUPPORTED_COLOR_SPACES: | ||
raise InvalidColorSpace( | ||
'unsupported color space: ' + str(color_space)) | ||
self.color_space = color_space | ||
|
||
def __str__(self): | ||
return self.color_space | ||
|
||
def __eq__(self, other): | ||
return self.color_space == other.color_space |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,106 @@ | ||
import numpy as np | ||
import math | ||
from color import Color | ||
from color_space import ColorSpace | ||
import utility | ||
|
||
|
||
class InvalidConversion(Exception): | ||
pass | ||
|
||
|
||
class ColorSpaceConverter: | ||
@staticmethod | ||
def rgb2hsv(self, color): | ||
color.value = color.value / 255. | ||
red, green, blue = color.value.tolist() | ||
|
||
max_val = max(color.value) | ||
min_val = min(color.value) | ||
diff = max_val - min_val | ||
|
||
if diff == 0: | ||
hue = 0 | ||
elif max_val == red: | ||
hue = (green - blue) / diff | ||
elif max_val == green: | ||
hue = (blue - red) / diff + 2 | ||
elif max_val == blue: | ||
hue = (red - green) / diff + 4 | ||
|
||
hue *= 60 | ||
hue = hue + 360 if hue < 0 else hue | ||
|
||
saturation = 0 if max_val == 0 else diff / max_val * 255 | ||
value = max_val * 255 | ||
hue *= 0.5 | ||
|
||
return Color(ColorSpace("HSV"), | ||
np.round(np.array([hue, saturation, value]))) | ||
|
||
@staticmethod | ||
def hsv2rgb(self, color): | ||
hue = color.value[0] * 2. / 360. * 6 | ||
saturation = color.value[1] / 255. | ||
value = color.value[2] / 255. | ||
|
||
chroma = value * saturation | ||
x = chroma * (1 - math.fabs(hue % 2 - 1)) | ||
rgb = [0] * Color.COLOR_DIM | ||
hue = hue % 6 | ||
|
||
if 0. <= hue < 1.: | ||
rgb = [chroma, x, 0] | ||
if 1. <= hue < 2.: | ||
rgb = [x, chroma, 0] | ||
if 2. <= hue < 3.: | ||
rgb = [0, chroma, x] | ||
if 3. <= hue < 4.: | ||
rgb = [0, x, chroma] | ||
if 4. <= hue < 5.: | ||
rgb = [x, 0, chroma] | ||
if 5. <= hue < 6.: | ||
rgb = [chroma, 0, x] | ||
|
||
min_val = value - chroma | ||
|
||
return Color(ColorSpace("RGB"), | ||
np.round((np.array(rgb) + min_val) * 255)) | ||
|
||
@staticmethod | ||
def rgb2lab(self, color): | ||
color.value = color.value / 255. | ||
# Convert RGB to XYZ. | ||
red, green, blue = [val * 100. for val in | ||
map(utility.rgb2xyz_nonlinear_transform, | ||
color.value.tolist())] | ||
|
||
conversion_mat = np.array([[0.412453, 0.357580, 0.180423], | ||
[0.212671, 0.715160, 0.072169], | ||
[0.019334, 0.119193, 0.950227]]) | ||
|
||
xyz = conversion_mat.dot( | ||
np.array([red, green, blue], dtype=np.float32)) | ||
|
||
# Convert XYZ to Lab. | ||
ref_point = np.array([95.047, 100., 108.883]) | ||
|
||
x_norm, y_norm, z_norm = map(utility.xyz2lab_nonlinear_transform, | ||
np.divide(xyz, ref_point).tolist()) | ||
|
||
l = (116. * y_norm - 16.) * 255. / 100. | ||
a = 500. * (x_norm - y_norm) + 128 | ||
b = 200. * (y_norm - z_norm) + 128 | ||
|
||
return Color(ColorSpace("LAB"), np.round(np.array([l, a, b]))) | ||
|
||
def convert(self, color, dst_space): | ||
if color.space == dst_space: | ||
return color | ||
|
||
converter_name = "{}2{}".format(color.space, dst_space).lower() | ||
if hasattr(ColorSpaceConverter, converter_name): | ||
color_pair_func = getattr(ColorSpaceConverter, converter_name) | ||
return color_pair_func(self, color) | ||
else: | ||
raise InvalidConversion("no converter for: " + converter_name) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,163 @@ | ||
import unittest | ||
import numpy as np | ||
|
||
from color_space import ColorSpace, InvalidColorSpace | ||
from color import Color, InvalidColorError | ||
from color_space_converter import ColorSpaceConverter, InvalidConversion | ||
|
||
|
||
class TestColorSpaceClass(unittest.TestCase): | ||
def test_can_create_empty_color_space(self): | ||
color_space = ColorSpace() | ||
self.assertTrue(isinstance(color_space, ColorSpace)) | ||
|
||
def test_can_create_default_rgb_color_space(self): | ||
color_space = ColorSpace() | ||
self.assertEqual(str(color_space), "RGB") | ||
|
||
def test_cannot_create_invalid_color_space(self): | ||
with self.assertRaises(InvalidColorSpace): | ||
ColorSpace("QQQ") | ||
|
||
def test_cannot_create_invalid_color_space_type(self): | ||
with self.assertRaises(InvalidColorSpace): | ||
ColorSpace(1) | ||
|
||
|
||
class TestColorClass(unittest.TestCase): | ||
def test_can_create_empty_color(self): | ||
color = Color() | ||
self.assertTrue(isinstance(color, Color)) | ||
|
||
def test_can_create_default_rgb_color(self): | ||
color = Color() | ||
self.assertEqual(str(color), "RGB [0, 0, 0]") | ||
|
||
def test_can_create_default_hsv_color(self): | ||
color = Color(ColorSpace("HSV")) | ||
self.assertEqual(str(color), "HSV [0, 0, 0]") | ||
|
||
def test_can_create_default_lab_color(self): | ||
color = Color(ColorSpace("LAB")) | ||
self.assertEqual(str(color), "LAB [0, 0, 0]") | ||
|
||
def test_can_create_rgb_color(self): | ||
color = Color(ColorSpace("RGB"), np.array([123, 45, 67])) | ||
self.assertEqual(str(color), "{} {}".format("RGB", | ||
np.array([123, 45, | ||
67]).tolist())) | ||
|
||
def test_cannot_create_invalid_rgb_color_len(self): | ||
rand_color = np.random.randint(0, 255, size=(1, 10)) | ||
with self.assertRaises(InvalidColorError): | ||
Color("RGB", rand_color) | ||
|
||
def test_cannot_create_invalid_rgb_color_val(self): | ||
rand_color = np.random.randint(300, 400, size=(1, Color.COLOR_DIM)) | ||
with self.assertRaises(InvalidColorError): | ||
Color(ColorSpace("RGB"), rand_color) | ||
|
||
def test_cannot_create_invalid_rgb_color_val_neg(self): | ||
rand_color = np.random.randint(-100, -10, size=(1, Color.COLOR_DIM)) | ||
with self.assertRaises(InvalidColorError): | ||
Color(ColorSpace("RGB"), rand_color) | ||
|
||
|
||
class TestColorSpaceConverterClass(unittest.TestCase): | ||
def setUp(self): | ||
self.converter = ColorSpaceConverter() | ||
|
||
def test_can_create_color_space_converter(self): | ||
self.assertTrue(isinstance(self.converter, ColorSpaceConverter)) | ||
|
||
def test_can_convert_rgb_to_rgb(self): | ||
color = Color() | ||
rgb_color = self.converter.convert(color, ColorSpace("RGB")) | ||
self.assertEqual(color, rgb_color) | ||
|
||
def test_can_convert_black_rgb_to_hsv(self): | ||
color = Color() | ||
hsv_color = self.converter.convert(color, ColorSpace("HSV")) | ||
self.assertEqual(hsv_color, Color(ColorSpace("HSV"))) | ||
|
||
def test_can_convert_simple_rgb_to_hsv(self): | ||
color = Color(ColorSpace("RGB"), np.array([0, 100, 0])) | ||
hsv_color = self.converter.convert(color, ColorSpace("HSV")) | ||
self.assertEquals(hsv_color, Color(ColorSpace("HSV"), | ||
np.array([60, 255, 100]))) | ||
|
||
def test_can_convert_rgb_to_hsv(self): | ||
color = Color(ColorSpace("RGB"), np.array([91, 71, 123])) | ||
hsv_color = self.converter.convert(color, ColorSpace("HSV")) | ||
self.assertEquals(hsv_color, Color(ColorSpace("HSV"), | ||
np.array([132, 108, 123]))) | ||
|
||
def test_can_convert_rgb_to_hsv_1(self): | ||
color = Color(ColorSpace("RGB"), np.array([191, 71, 123])) | ||
hsv_color = self.converter.convert(color, ColorSpace("HSV")) | ||
self.assertEquals(hsv_color, Color(ColorSpace("HSV"), | ||
np.array([167, 160, 191]))) | ||
|
||
def test_can_convert_black_hsv_to_rgb(self): | ||
color = Color(ColorSpace("HSV")) | ||
rgb_color = self.converter.convert(color, ColorSpace("RGB")) | ||
self.assertEqual(rgb_color, Color(ColorSpace("RGB"))) | ||
|
||
def test_can_convert_simple_hsv_to_rgb(self): | ||
color = Color(ColorSpace("HSV"), np.array([0, 100, 0])) | ||
rgb_color = self.converter.convert(color, ColorSpace("RGB")) | ||
self.assertEqual(rgb_color, Color(ColorSpace("RGB"), | ||
np.array([0, 0, 0]))) | ||
|
||
def test_can_convert_hsv_to_rgb_2(self): | ||
color = Color(ColorSpace("HSV"), np.array([40, 108, 123])) | ||
rgb_color = self.converter.convert(color, ColorSpace("RGB")) | ||
self.assertEqual(rgb_color, Color(ColorSpace("RGB"), | ||
np.array([106, 123, 71]))) | ||
|
||
def test_can_convert_hsv_to_rgb_3(self): | ||
color = Color(ColorSpace("HSV"), np.array([80, 108, 123])) | ||
rgb_color = self.converter.convert(color, ColorSpace("RGB")) | ||
self.assertEqual(rgb_color, Color(ColorSpace("RGB"), | ||
np.array([71, 123, 106]))) | ||
|
||
def test_can_convert_hsv_to_rgb_4(self): | ||
color = Color(ColorSpace("HSV"), np.array([100, 50, 60])) | ||
rgb_color = self.converter.convert(color, ColorSpace("RGB")) | ||
self.assertEqual(rgb_color, Color(ColorSpace("RGB"), | ||
np.array([48, 56, 60]))) | ||
|
||
def test_can_convert_hsv_to_rgb_5(self): | ||
color = Color(ColorSpace("HSV"), np.array([132, 108, 123])) | ||
rgb_color = self.converter.convert(color, ColorSpace("RGB")) | ||
self.assertEqual(rgb_color, Color(ColorSpace("RGB"), | ||
np.array([92, 71, 123]))) | ||
|
||
def test_can_convert_hsv_to_rgb_6(self): | ||
color = Color(ColorSpace("HSV"), np.array([175, 108, 123])) | ||
rgb_color = self.converter.convert(color, ColorSpace("RGB")) | ||
self.assertEqual(rgb_color, Color(ColorSpace("RGB"), | ||
np.array([123, 71, 80]))) | ||
|
||
def test_can_convert_black_rgb_to_lab(self): | ||
color = Color() | ||
lab_color = self.converter.convert(color, ColorSpace("LAB")) | ||
self.assertEqual(lab_color, Color(ColorSpace("LAB"), | ||
np.array([0, 128, 128]))) | ||
|
||
def test_can_convert_simple_rgb_to_lab(self): | ||
color = Color(ColorSpace("RGB"), np.array([0, 100, 0])) | ||
lab_color = self.converter.convert(color, ColorSpace("LAB")) | ||
self.assertEqual(lab_color, Color(ColorSpace("LAB"), | ||
np.array([92.0, 85.0, 170.0]))) | ||
|
||
def test_can_convert_rgb_to_lab(self): | ||
color = Color(ColorSpace("RGB"), np.array([91, 71, 123])) | ||
lab_color = self.converter.convert(color, ColorSpace("LAB")) | ||
self.assertEqual(lab_color, Color(ColorSpace("LAB"), | ||
np.array([88, 148, 101]))) | ||
|
||
def test_cannot_create_unimplemented_converter(self): | ||
color = Color(ColorSpace("LAB")) | ||
with self.assertRaises(InvalidConversion): | ||
self.converter.convert(color, ColorSpace("RGB")) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
import math | ||
|
||
|
||
def xyz2lab_nonlinear_transform(t): | ||
if t > 0.008856: | ||
return math.pow(t, 1. / 3) | ||
else: | ||
return 7.787 * t + 16. / 116 | ||
|
||
|
||
def rgb2xyz_nonlinear_transform(t): | ||
if t <= 0.04045: | ||
return t / 12.92 | ||
else: | ||
return math.pow(((t + 0.055) / 1.055), 2.4) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
# Матрицы. Заполнение, вычисление детерминанта | ||
|
||
### Выполнила: | ||
|
||
- Тимонова Анастасия | ||
- ННГУ, ИИТММ, каф. МОСТ, группа М0816-1 | ||
|
||
### Задание: | ||
1. Разработать приложение для заполнения матрицы и вычисления её детерминанта. | ||
2. Для матриц более высокого порядка, чем 2х2 или 3х3, при необходимости, можно использовать метод Гаусса для повышения эффективности вычислений. | ||
|
||
Некоторые сведения можно найти в учебной литературе и статьях: | ||
- А.Г. Курош ["Курс высшей алгебры"](vilenin.narod.ru/Mm/Books/65/book65_1.pdf) | ||
- [Определитель](https://ru.wikipedia.org/wiki/%D0%9E%D0%BF%D1%80%D0%B5%D0%B4%D0%B5%D0%BB%D0%B8%D1%82%D0%B5%D0%BB%D1%8C) и [Метод Гаусса](https://ru.wikipedia.org/wiki/%D0%9C%D0%B5%D1%82%D0%BE%D0%B4_%D0%93%D0%B0%D1%83%D1%81%D1%81%D0%B0) на сайте Wikipedia | ||
|
||
### Документация разработчика: | ||
|
||
TBD |