Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

新增涂改算法 #49

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 42 additions & 4 deletions handright/_core.py
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ def _draw_page(
while y <= height - bottom_margin - font_size:
x = left_margin
while True:
if text[start] == _LF:
if text[start] == _LF: #跳过换行符自己处理
start += 1
if start == len(text):
return start
Expand All @@ -120,6 +120,26 @@ def _draw_page(
if (x > width - right_margin - font_size
and text[start] not in end_chars):
break

# 随机选择一个字符进行替换 9.1
if rand.random() < tpl.get_strikethrough_probability():
wrong_char_index = random.randint(0, len(text) - 1)
wrong_end_chars = end_chars + ' '
# 检查字符是否在排除列表中
while text[wrong_char_index] in wrong_end_chars:
wrong_char_index = random.randint(0, len(text) - 1)
wrong_char = text[wrong_char_index]

origin_x =x
# 绘制错误的字(被划掉的字)
if Feature.GRID_LAYOUT in tpl.get_features():
x = _grid_layout(draw, x, y, wrong_char, tpl, rand)
else:
x = _flow_layout(draw, x, y, wrong_char, tpl, rand)
# 添加涂改标记(斜线)
_draw_strikethrough(draw, origin_x, y, tpl, rand)

# 绘制正确的字
if Feature.GRID_LAYOUT in tpl.get_features():
x = _grid_layout(draw, x, y, text[start], tpl, rand)
else:
Expand All @@ -130,6 +150,24 @@ def _draw_page(
y += line_spacing
return start

def _draw_strikethrough(draw, x, y, tpl, rand):
line_length = tpl.get_font().size * math.sqrt(2)
length_sigma = tpl.get_strikethrough_length_sigma()
angle_sigma = tpl.get_strikethrough_angle_sigma()
width_sigma = tpl.get_strikethrough_width_sigma()
line_width = tpl.get_strikethrough_width()

start_x = x + 1/7*line_length
start_y = y + 1/7*line_length
# 添加扰动
actual_length = line_length + gauss(rand, 0, length_sigma)
initial_angle = 45 # 初始角度设置为45度
actual_angle = initial_angle + gauss(rand, 0, angle_sigma)
actual_width = line_width + gauss(rand, 0, width_sigma) # 假设基础宽度为5

end_x = start_x + actual_length * math.cos(math.radians(actual_angle))*5/7
end_y = start_y + actual_length * math.sin(math.radians(actual_angle))*5/7
draw.line((start_x, start_y, end_x, end_y), fill=_WHITE, width=int(actual_width))

def _flow_layout(
draw, x, y, char, tpl: Template, rand: random.Random
Expand All @@ -152,7 +190,7 @@ def _grid_layout(
round(gauss(rand, y, tpl.get_line_spacing_sigma())))
font = _get_font(tpl, rand)
_ = _draw_char(draw, char, xy, font)
x += tpl.get_word_spacing() + tpl.get_font().size
x += tpl.get_word_spacing() + tpl.get_font().size#主要的区别在于这里的X它是固定的
return x


Expand Down Expand Up @@ -246,10 +284,10 @@ def _extract_stroke(
bitmap, start: Tuple[int, int], strokes, bbox: Tuple[int, int, int, int]
) -> None:
"""Helper function of _extract_strokes() which uses depth first search to
find the pixels of a glyph."""
find the pixels of a glyph. 修改了传入的 strokes 参数"""
left, upper, right, lower = bbox
stack = [start, ]
while stack:
while stack:#白色是1,為true
x, y = stack.pop()
if y - 1 >= upper and bitmap[x, y - 1] and strokes.add(_xy(x, y - 1)):
stack.append((x, y - 1))
Expand Down
83 changes: 81 additions & 2 deletions handright/_template.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,11 @@ class Template(object):
"_perturb_x_sigma",
"_perturb_y_sigma",
"_perturb_theta_sigma",
"_strikethrough_length_sigma",
"_strikethrough_angle_sigma",
"_strikethrough_width_sigma",
"_strikethrough_probability",
"_strikethrough_width",
"_features",
)

Expand All @@ -46,6 +51,11 @@ class Template(object):
_DEFAULT_END_CHARS = ",。》?;:’”】}、!%),.>?;:]}!%)′″℃℉"

_DEFAULT_PERTURB_THETA_SIGMA = 0.07

_DEFAULT_strikethrough_width_sigma = 2
_DEFAULT_strikethrough_angle_sigma = 2
_DEFAULT_strikethrough_probability = 0


_DEFAULT_FEATURES = frozenset()

Expand All @@ -68,6 +78,11 @@ def __init__(
perturb_x_sigma: Optional[float] = None,
perturb_y_sigma: Optional[float] = None,
perturb_theta_sigma: float = _DEFAULT_PERTURB_THETA_SIGMA,
strikethrough_length_sigma: Optional[float]=None,
strikethrough_angle_sigma: float = _DEFAULT_strikethrough_angle_sigma,
strikethrough_width_sigma: Optional[float]=None,
strikethrough_probability: float = _DEFAULT_strikethrough_probability,
strikethrough_width: Optional[float]=None,
features: Set = _DEFAULT_FEATURES,
):
"""Note that, all the Integer parameters are in pixels.
Expand Down Expand Up @@ -117,6 +132,11 @@ def __init__(
self.set_perturb_x_sigma(perturb_x_sigma)
self.set_perturb_y_sigma(perturb_y_sigma)
self.set_perturb_theta_sigma(perturb_theta_sigma)
self.set_strikethrough_length_sigma(strikethrough_length_sigma)
self.set_strikethrough_angle_sigma(strikethrough_angle_sigma)
self.set_strikethrough_width_sigma(strikethrough_width_sigma)
self.set_strikethrough_probability(strikethrough_probability)
self.set_strikethrough_width(strikethrough_width)
self.set_features(features)

def __eq__(self, other) -> bool:
Expand All @@ -138,7 +158,12 @@ def __eq__(self, other) -> bool:
and self._end_chars == other._end_chars
and self._perturb_x_sigma == other._perturb_x_sigma
and self._perturb_y_sigma == other._perturb_y_sigma
and self._perturb_theta_sigma == other._perturb_theta_sigma)
and self._perturb_theta_sigma == other._perturb_theta_sigma
and self._strikethrough_length_sigma == other._strikethrough_length_sigma
and self._strikethrough_angle_sigma == other._strikethrough_angle_sigma
and self._strikethrough_width_sigma == other._strikethrough_width_sigma
and self._strikethrough_probability == other._strikethrough_probability
and self._strikethrough_width == other._strikethrough_width)

def set_background(self, background: PIL.Image.Image) -> None:
self._background = background
Expand Down Expand Up @@ -237,6 +262,40 @@ def set_perturb_theta_sigma(
) -> None:
self._perturb_theta_sigma = perturb_theta_sigma

def set_strikethrough_length_sigma(
self, strikethrough_length_sigma: Optional[float] = None
) -> None:
if strikethrough_length_sigma is None:
self._strikethrough_length_sigma = self._font.size / 32
else:
self._strikethrough_length_sigma = strikethrough_length_sigma

def set_strikethrough_width_sigma(
self, strikethrough_width_sigma: Optional[float] = None
) -> None:
if strikethrough_width_sigma is None:
self._strikethrough_width_sigma = self._font.size / 32
else:
self._strikethrough_width_sigma = strikethrough_width_sigma

def set_strikethrough_probability(
self, strikethrough_probability: float = _DEFAULT_strikethrough_probability
) -> None:
self._strikethrough_probability = strikethrough_probability

def set_strikethrough_width(
self, strikethrough_width: Optional[float] = None
) -> None:
if strikethrough_width is None:
self._strikethrough_width = self._font.size / 32
else:
self._strikethrough_width = strikethrough_width

def set_strikethrough_angle_sigma(
self, strikethrough_angle_sigma: float = _DEFAULT_strikethrough_angle_sigma
)-> None:
self._strikethrough_angle_sigma = strikethrough_angle_sigma

def get_background(self) -> PIL.Image.Image:
return self._background

Expand Down Expand Up @@ -290,6 +349,21 @@ def get_perturb_y_sigma(self) -> float:

def get_perturb_theta_sigma(self) -> float:
return self._perturb_theta_sigma

def get_strikethrough_length_sigma(self):
return self._strikethrough_length_sigma

def get_strikethrough_angle_sigma(self):
return self._strikethrough_angle_sigma

def get_strikethrough_width_sigma(self):
return self._strikethrough_width_sigma

def get_strikethrough_probability(self):
return self._strikethrough_probability

def get_strikethrough_width(self):
return self._strikethrough_width

def get_size(self) -> Tuple[int, int]:
return self.get_background().size
Expand Down Expand Up @@ -320,7 +394,12 @@ def __repr__(self) -> str:
"end_chars={self._end_chars}, "
"perturb_x_sigma={self._perturb_x_sigma}, "
"perturb_y_sigma={self._perturb_y_sigma}, "
"perturb_theta_sigma={self._perturb_theta_sigma})"
"perturb_theta_sigma={self._perturb_theta_sigma},"
"strikethrough_length_sigma == {self._strikethrough_length_sigma},"
"strikethrough_angle_sigma == {self._strikethrough_angle_sigma},"
"strikethrough_width_sigma == {self._strikethrough_width_sigma},"
"strikethrough_probability == {self._strikethrough_probability},"
"strikethrough_width == {self._strikethrough_width})"
).format(class_name=class_name, self=self)


Expand Down