keinne commited on
Commit
af3a707
·
verified ·
1 Parent(s): 3eb4bfd

Upload 5 files

Browse files
Files changed (5) hide show
  1. .gitattributes +1 -0
  2. README.md +45 -11
  3. app.py +4 -1
  4. livro.py +3 -14
  5. screenshot-dot2dot.jpg +3 -0
.gitattributes CHANGED
@@ -33,3 +33,4 @@ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
33
  *.zip filter=lfs diff=lfs merge=lfs -text
34
  *.zst filter=lfs diff=lfs merge=lfs -text
35
  *tfevents* filter=lfs diff=lfs merge=lfs -text
 
 
33
  *.zip filter=lfs diff=lfs merge=lfs -text
34
  *.zst filter=lfs diff=lfs merge=lfs -text
35
  *tfevents* filter=lfs diff=lfs merge=lfs -text
36
+ screenshot-dot2dot.jpg filter=lfs diff=lfs merge=lfs -text
README.md CHANGED
@@ -1,15 +1,49 @@
 
 
 
 
 
1
  ---
2
- title: Dot2dot
3
- emoji: 💻
4
- colorFrom: red
5
- colorTo: blue
6
- sdk: gradio
7
- sdk_version: 5.29.0
8
- app_file: app.py
9
- pinned: false
10
- license: mit
11
- short_description: Create a Dot-to-Dot Fun for Kids Ages 4-12
 
12
  ---
13
 
14
- Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
15
 
 
 
1
+
2
+ # ✏️ Dot2Dot Pro – Gerador de Livros de Ligar os Pontos para KDP
3
+
4
+ Transforme qualquer imagem em um livro infantil de "ligar os pontos", pronto para publicar na Amazon KDP!
5
+
6
  ---
7
+
8
+ ## 🧠 Recursos do App
9
+
10
+ - 📐 **Centralização do desenho** (topo, meio ou base da página)
11
+ - 🧽 **Marcação de áreas preservadas**: desenhe regiões que **não devem ser convertidas em pontos**
12
+ - 🎯 **Distribuição inteligente dos pontos**: menor número possível com fidelidade visual
13
+ - 🔢 **Sequência lógica e espaçamento coerente** entre os pontos
14
+ - 👁 **Prévia com sobreposição 50% da imagem original**
15
+ - 📥 **Exportação em PDF e PNG** no formato 8.5x11" (KDP)
16
+ - ⚙️ Totalmente compatível com o fluxo de publicação da Amazon
17
+
18
  ---
19
 
20
+ ## 🖼️ Exemplo da Interface
21
+
22
+ ![preview](screenshot-dot2dot.jpg)
23
+
24
+ ---
25
+
26
+ ## 🖼️ Como Usar
27
+
28
+ 1. Envie uma imagem em preto e branco com contornos bem definidos
29
+ 2. Marque áreas que **devem ser preservadas** (olhos, bocas, contornos internos etc.)
30
+ 3. Defina a idade da criança (isso ajusta o número de pontos)
31
+ 4. Escolha a posição do desenho na página
32
+ 5. Clique em **Gerar Pontos**
33
+ 6. Visualize:
34
+ - A prévia com numeração
35
+ - A versão sobreposta para validação
36
+ 7. Clique em **Salvar como PDF** ou **Salvar como PNG**
37
+ 8. Pronto! Seu arquivo está pronto para a KDP
38
+
39
+ ---
40
+
41
+ ## 🛠️ Sugestões de uso
42
+
43
+ - 🐤 Ideal para ilustrações vetoriais de animais, personagens, veículos etc.
44
+ - ✍️ Dê preferência a fundos brancos e traços escuros
45
+ - 📏 Imagens de 800x600 pixels ou mais funcionam melhor
46
+
47
+ ---
48
 
49
+ Criado com 💡 para editores criativos e autores independentes.
app.py CHANGED
@@ -5,7 +5,8 @@ from livro import processar_e_mostrar, verificar_contraste, gerar_preview_kdp
5
  with gr.Blocks() as demo:
6
  with gr.Row():
7
  imagem_input = gr.Image(label="Imagem Original", type="numpy")
8
- mascara = gr.ImageEditor(label="Marcar áreas para preservar (opcional)")
 
9
  with gr.Row():
10
  idade = gr.Slider(minimum=4, maximum=12, step=1, value=6, label="Idade da criança (ajusta número de pontos)")
11
  posicao = gr.Radio(["Topo da página", "Centro da página", "Base da página"], value="Centro da página", label="Posicionamento do desenho")
@@ -44,6 +45,8 @@ with gr.Blocks() as demo:
44
  def gerar_capa():
45
  return gerar_preview_kdp()
46
 
 
 
47
  gerar_btn.click(gerar, inputs=[imagem_input, mascara, idade, posicao], outputs=[contraste_alerta, imagem_resultado, sobreposicao])
48
  salvar_btn.click(salvar_pdf, outputs=saida_pdf)
49
  salvar_png.click(salvar_imagem, outputs=saida_png)
 
5
  with gr.Blocks() as demo:
6
  with gr.Row():
7
  imagem_input = gr.Image(label="Imagem Original", type="numpy")
8
+ with gr.Row():
9
+ mascara = gr.ImageEditor(label="Marcar áreas para preservar (opcional)", type="numpy", tool="brush", interactive=True)
10
  with gr.Row():
11
  idade = gr.Slider(minimum=4, maximum=12, step=1, value=6, label="Idade da criança (ajusta número de pontos)")
12
  posicao = gr.Radio(["Topo da página", "Centro da página", "Base da página"], value="Centro da página", label="Posicionamento do desenho")
 
45
  def gerar_capa():
46
  return gerar_preview_kdp()
47
 
48
+ imagem_input.change(fn=lambda img: img, inputs=imagem_input, outputs=mascara)
49
+
50
  gerar_btn.click(gerar, inputs=[imagem_input, mascara, idade, posicao], outputs=[contraste_alerta, imagem_resultado, sobreposicao])
51
  salvar_btn.click(salvar_pdf, outputs=saida_pdf)
52
  salvar_png.click(salvar_imagem, outputs=saida_png)
livro.py CHANGED
@@ -12,17 +12,14 @@ PAGE_HEIGHT = 11.5 * inch
12
  MARGIN = 0.5 * inch
13
 
14
  def verificar_contraste(imagem_array):
15
- # Converte para escala de cinza e calcula o desvio padrão para avaliar contraste
16
  gray = cv2.cvtColor(imagem_array, cv2.COLOR_BGR2GRAY)
17
  contrast = gray.std()
18
  return "⚠️ Baixo contraste detectado!" if contrast < 30 else "✅ Contraste adequado."
19
 
20
  def detectar_pontos(imagem_array, mascara_array, idade, distancia_maxima=50):
21
- # Preprocessamento da imagem
22
  gray = cv2.cvtColor(imagem_array, cv2.COLOR_BGR2GRAY)
23
  _, thresh = cv2.threshold(gray, 200, 255, cv2.THRESH_BINARY_INV)
24
 
25
- # Aplica a máscara para preservar regiões (remover pontos dessas áreas)
26
  if mascara_array is not None and isinstance(mascara_array, np.ndarray):
27
  try:
28
  mask_gray = cv2.cvtColor(mascara_array, cv2.COLOR_BGR2GRAY)
@@ -31,30 +28,24 @@ def detectar_pontos(imagem_array, mascara_array, idade, distancia_maxima=50):
31
  except Exception as e:
32
  print("Erro ao processar máscara:", e)
33
 
34
- # Encontra contornos
35
  contours, _ = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)
36
  if not contours:
37
  return [], None
38
 
39
  main_contour = max(contours, key=cv2.contourArea)
40
-
41
- # Reduz a quantidade de pontos mantendo a forma
42
- epsilon = 1.0 # Quanto maior, mais simplificado
43
  simplified = cv2.approxPolyDP(main_contour, epsilon, closed=False)
44
-
45
- # Ajusta número com base na idade da criança
46
  max_pontos = min(30 + (idade - 4) * 10, 100)
47
  step = max(1, len(simplified) // max_pontos)
48
  pontos = [tuple(pt[0]) for pt in simplified[::step]]
49
 
50
- # Organiza sequencialmente para evitar pontos muito distantes
51
  if len(pontos) > 2:
52
  ordenados = [pontos[0]]
53
  restantes = pontos[1:]
54
  while restantes:
55
  ultimo = ordenados[-1]
56
  prox = min(restantes, key=lambda p: np.hypot(p[0]-ultimo[0], p[1]-ultimo[1]))
57
- if np.hypot(p[0]-ultimo[0], p[1]-ultimo[1]) > distancia_maxima:
58
  break
59
  ordenados.append(prox)
60
  restantes.remove(prox)
@@ -65,7 +56,6 @@ def normalizar_para_preview(pontos, largura=600, altura=800, margem=50, posicao=
65
  if not pontos:
66
  return [], 0
67
 
68
- # Escala os pontos para caber no canvas
69
  x_coords, y_coords = zip(*pontos)
70
  min_x, max_x = min(x_coords), max(x_coords)
71
  min_y, max_y = min(y_coords), max(y_coords)
@@ -78,7 +68,7 @@ def normalizar_para_preview(pontos, largura=600, altura=800, margem=50, posicao=
78
  offset_y = margem
79
  elif posicao == "Base da página":
80
  offset_y = altura - margem - altura_desenho
81
- else: # Centro
82
  offset_y = (altura - altura_desenho) // 2
83
 
84
  pontos_normalizados = [(
@@ -105,7 +95,6 @@ def gerar_overlay(original, pontos_norm):
105
  overlay = original.copy()
106
  h, w = overlay.shape[:2]
107
  resize = cv2.resize(overlay, (w, h))
108
-
109
  transparente = cv2.addWeighted(resize, 0.5, np.ones_like(resize) * 255, 0.5, 0)
110
 
111
  for i, (x, y) in enumerate(pontos_norm):
 
12
  MARGIN = 0.5 * inch
13
 
14
  def verificar_contraste(imagem_array):
 
15
  gray = cv2.cvtColor(imagem_array, cv2.COLOR_BGR2GRAY)
16
  contrast = gray.std()
17
  return "⚠️ Baixo contraste detectado!" if contrast < 30 else "✅ Contraste adequado."
18
 
19
  def detectar_pontos(imagem_array, mascara_array, idade, distancia_maxima=50):
 
20
  gray = cv2.cvtColor(imagem_array, cv2.COLOR_BGR2GRAY)
21
  _, thresh = cv2.threshold(gray, 200, 255, cv2.THRESH_BINARY_INV)
22
 
 
23
  if mascara_array is not None and isinstance(mascara_array, np.ndarray):
24
  try:
25
  mask_gray = cv2.cvtColor(mascara_array, cv2.COLOR_BGR2GRAY)
 
28
  except Exception as e:
29
  print("Erro ao processar máscara:", e)
30
 
 
31
  contours, _ = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)
32
  if not contours:
33
  return [], None
34
 
35
  main_contour = max(contours, key=cv2.contourArea)
36
+ epsilon = 1.0
 
 
37
  simplified = cv2.approxPolyDP(main_contour, epsilon, closed=False)
 
 
38
  max_pontos = min(30 + (idade - 4) * 10, 100)
39
  step = max(1, len(simplified) // max_pontos)
40
  pontos = [tuple(pt[0]) for pt in simplified[::step]]
41
 
 
42
  if len(pontos) > 2:
43
  ordenados = [pontos[0]]
44
  restantes = pontos[1:]
45
  while restantes:
46
  ultimo = ordenados[-1]
47
  prox = min(restantes, key=lambda p: np.hypot(p[0]-ultimo[0], p[1]-ultimo[1]))
48
+ if np.hypot(prox[0] - ultimo[0], prox[1] - ultimo[1]) > distancia_maxima:
49
  break
50
  ordenados.append(prox)
51
  restantes.remove(prox)
 
56
  if not pontos:
57
  return [], 0
58
 
 
59
  x_coords, y_coords = zip(*pontos)
60
  min_x, max_x = min(x_coords), max(x_coords)
61
  min_y, max_y = min(y_coords), max(y_coords)
 
68
  offset_y = margem
69
  elif posicao == "Base da página":
70
  offset_y = altura - margem - altura_desenho
71
+ else:
72
  offset_y = (altura - altura_desenho) // 2
73
 
74
  pontos_normalizados = [(
 
95
  overlay = original.copy()
96
  h, w = overlay.shape[:2]
97
  resize = cv2.resize(overlay, (w, h))
 
98
  transparente = cv2.addWeighted(resize, 0.5, np.ones_like(resize) * 255, 0.5, 0)
99
 
100
  for i, (x, y) in enumerate(pontos_norm):
screenshot-dot2dot.jpg ADDED

Git LFS Details

  • SHA256: 26297e2ca1142ef428c86f8beae119066e0bbe618237fcd04e824cae63b6df0c
  • Pointer size: 131 Bytes
  • Size of remote file: 127 kB