{"id":24508373,"url":"https://github.com/frankson18/processamento-digital-imagens","last_synced_at":"2026-05-10T02:26:07.919Z","repository":{"id":139861429,"uuid":"388305068","full_name":"Frankson18/processamento-digital-imagens","owner":"Frankson18","description":"Resolução de exercícios para a matéria de Processamento Digital de Imagens da UFRN. Utilizando a biblioteca OpenCV na linguagem C++.","archived":false,"fork":false,"pushed_at":"2021-08-27T04:52:13.000Z","size":22051,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-01-22T00:15:40.181Z","etag":null,"topics":["opencv","processing-images","python","python3"],"latest_commit_sha":null,"homepage":"https://frankson18.github.io/processamento-digital-imagens/","language":"C++","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Frankson18.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2021-07-22T02:33:35.000Z","updated_at":"2021-09-16T00:04:15.000Z","dependencies_parsed_at":null,"dependency_job_id":"204e66fd-d65e-4d5a-b7ba-3f4e8f12bd31","html_url":"https://github.com/Frankson18/processamento-digital-imagens","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Frankson18%2Fprocessamento-digital-imagens","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Frankson18%2Fprocessamento-digital-imagens/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Frankson18%2Fprocessamento-digital-imagens/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Frankson18%2Fprocessamento-digital-imagens/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Frankson18","download_url":"https://codeload.github.com/Frankson18/processamento-digital-imagens/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":243707868,"owners_count":20334712,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["opencv","processing-images","python","python3"],"created_at":"2025-01-22T00:15:47.587Z","updated_at":"2026-05-10T02:26:02.889Z","avatar_url":"https://github.com/Frankson18.png","language":"C++","funding_links":[],"categories":[],"sub_categories":[],"readme":"# PROCESSAMENTO DIGITAL DE IMAGENS - EXERCICIOS\n\n# INTRODUÇÃO\n\nResolução de exercícios para a matéria de Processamento Digital de Imagens da UFRN. Utilizando a biblioteca `OpenCV` na linguagem `C++`.\n\n# PRIMEIRA UNIDADE\n\n# MANIPULANDO PIXEIS EM UMA IMAGEM\n\n### EXERCÍCIO 1.1\n\nUtilizando o programa [exemplos/pixels.cpp](https://agostinhobritojr.github.io/tutorial/pdi/exemplos/pixels.cpp) como referência, implemente um programa `regions.cpp`. Esse programa deverá solicitar ao usuário as coordenadas de dois pontos P1 e P2 localizados dentro dos limites do tamanho da imagem e exibir que lhe for fornecida. Entretanto, a região definida pelo retângulo de vértices opostos definidos pelos pontos P1 e P2 será exibida com o negativo da imagem na região correspondente. \n\n---\n\n### SOLUÇÃO\n\nPara resolver foi preciso implementar entradas para o usuário escolher qual região ele queria deixar em negativo. Para deixar deixar a região em negativo foi feito um `for` para percorrer área escolhida e fazer a operação `image.at\u003cuchar\u003e(i,j)=255 - image.at\u003cuchar\u003e(i,j);` que faz com que o pixel da imagem se torne negativo. \n\n![PROCESSAMENTO%20DIGITAL%20DE%20IMAGENS%20-%20EXERCICIOS%202870481b40d7467da90e6c6ee9cd04c5/Untitled.png](PROCESSAMENTO%20DIGITAL%20DE%20IMAGENS%20-%20EXERCICIOS%202870481b40d7467da90e6c6ee9cd04c5/Untitled.png)\n\n![PROCESSAMENTO%20DIGITAL%20DE%20IMAGENS%20-%20EXERCICIOS%202870481b40d7467da90e6c6ee9cd04c5/Untitled%201.png](PROCESSAMENTO%20DIGITAL%20DE%20IMAGENS%20-%20EXERCICIOS%202870481b40d7467da90e6c6ee9cd04c5/Untitled%201.png)\n\n```cpp\n#include \u003ciostream\u003e\n#include \u003copencv2/opencv.hpp\u003e\n\nusing namespace cv;\nusing namespace std;\n\nint main(int, char** argv){\n  Mat image;\n  int x1,y1,x2,y2;\n\n  namedWindow(\"Original\",WINDOW_AUTOSIZE);\n  image = imread(argv[1],IMREAD_GRAYSCALE);\n\n  if(!image.data){\n    cout \u003c\u003c \"nao abriu bolhas.png\" \u003c\u003c std::endl;\n  }\n  imshow(\"Original\", image);\n  waitKey();\n\n  cout \u003c\u003c \"Ditite as coordenadas do primeiro ponto: \"\u003c\u003cendl;\n  cin \u003e\u003e x1 \u003e\u003e y1;\n  cout \u003c\u003c \"Ditite as coordenadas do primeiro ponto: \"\u003c\u003cendl;\n  cin \u003e\u003e x2 \u003e\u003e y2; \n  \n  //Verifica se os pontos são validos\n  if(x1!=x2 \u0026\u0026 y1!=y2 \u0026\u0026x1\u003e=0 \u0026\u0026 x2\u003c=image.rows \u0026\u0026 y1\u003e=0 \u0026\u0026 y2\u003c=image.rows){\n    //faz a o negativo da região escolhida\n    for(int i=x1;i\u003cx2;i++){\n      for(int j=y1;j\u003cy2;j++){\n        image.at\u003cuchar\u003e(i,j)=255 - image.at\u003cuchar\u003e(i,j);\n      }\n    }\n\n    namedWindow(\"Negativo\", WINDOW_AUTOSIZE);\n    imshow(\"Negativo\", image);\n    waitKey(); \n       \n  }else{\n    cout\u003c\u003c\"coordenadas invalidas\"\u003c\u003cendl;\n  }\n\n  \n  return 0;\n}\n```\n\n### EXERCÍCIO 1.2\n\nUtilizando o programa [exemplos/pixels.cpp](https://agostinhobritojr.github.io/tutorial/pdi/exemplos/pixels.cpp) como referência, implemente um programa `trocaregioes.cpp`. Seu programa deverá trocar os quadrantes em diagonal na imagem. Explore o uso da classe Mat e seus construtores para criar as regiões que serão trocadas.\n\n---\n\n### SOLUÇÃO\n\nDiferente do regions, esse agora não precisa de interação com o usuário, é simplesmente manipulação da imagem. E para fazer isso foi usado a classe `Mat` e as funções `Rect` para pegar pedaços da imagem e salva-los em uma matriz e o método `copyTo` para fazer a modificação na imagem atual, assim conseguindo modificar as áreas da imagem.\n\n![PROCESSAMENTO%20DIGITAL%20DE%20IMAGENS%20-%20EXERCICIOS%202870481b40d7467da90e6c6ee9cd04c5/Untitled.png](PROCESSAMENTO%20DIGITAL%20DE%20IMAGENS%20-%20EXERCICIOS%202870481b40d7467da90e6c6ee9cd04c5/Untitled.png)\n\n![PROCESSAMENTO%20DIGITAL%20DE%20IMAGENS%20-%20EXERCICIOS%202870481b40d7467da90e6c6ee9cd04c5/Untitled%202.png](PROCESSAMENTO%20DIGITAL%20DE%20IMAGENS%20-%20EXERCICIOS%202870481b40d7467da90e6c6ee9cd04c5/Untitled%202.png)\n\n```cpp\n#include \u003ciostream\u003e\n#include \u003copencv2/opencv.hpp\u003e\n\nusing namespace cv;\nusing namespace std;\n\nint main(int, char** argv){\n  Mat image;\n\n  namedWindow(\"Original\",WINDOW_AUTOSIZE);\n  image = imread(argv[1],IMREAD_GRAYSCALE);\n\n  if(!image.data){\n    cout \u003c\u003c \"nao abriu bolhas.png\" \u003c\u003c std::endl;\n  }\n  imshow(\"Original\", image);\n  waitKey();\n\n  //recorte superior esquerdo da imagem\n  Mat rec1 = image(Rect(0,0,image.rows/2,image.cols/2)); \n  //recorte superior direito da imagem\n  Mat rec2 = image(Rect(image.rows/2,0,image.rows/2,image.cols/2));\n  // recorte inferior esquerdo\n  Mat rec3 = image(Rect(0,image.cols/2,image.rows/2,image.cols/2));\n  // recorte inferior direito\n  Mat rec4 = image(Rect(image.rows/2,image.cols/2,image.rows/2,image.cols/2));\n\n  Mat troca(image.rows,image.cols,image.type());\n\n  // trocando inferior direito para o superior esquerdo\n  rec4.copyTo(troca(Rect(0,0,image.rows/2,image.cols/2)));\n  // trocando inferior esquerdo para o superior direito\n  rec3.copyTo(troca(Rect(image.rows/2,0,image.rows/2,image.cols/2)));\n  // trocando superior direito para inferior direito\n  rec2.copyTo(troca(Rect(0,image.cols/2,image.rows/2,image.cols/2)));\n  // trocando superior esquerdo para inferior direito \n  rec1.copyTo(troca(Rect(image.rows/2,image.cols/2,image.rows/2,image.cols/2)));\n\n  namedWindow(\"regioes trocadas\", WINDOW_AUTOSIZE);\n  imshow(\"regioes trocadas\", troca);\n  waitKey();    \n  \n\n  \n  return 0;\n}\n```\n\n---\n\n# PREENCHENDO REGIÕES\n\n### EXERCÍCIO 2.1\n\nObservando-se o programa [labeling.cpp](https://agostinhobritojr.github.io/tutorial/pdi/exemplos/labeling.cpp) como exemplo, é possível verificar que caso existam mais de 255 objetos na cena, o processo de rotulação poderá ficar comprometido. Identifique a situação em que isso ocorre e proponha uma solução para este problema.\n\n### SOLUÇÃO\n\nPara resolver o problema de casos que a imagem tenha mais que 255 objetos a serem rotulados, podemos usar uma estrategia de fazer o rotulo ser decimal, ou rotula usando a operação mod de 255. \n\n### EXERCÍCIO 2.2\n\nAprimore o algoritmo de contagem apresentado para identificar regiões com ou sem buracos internos que existam na cena. Assuma que objetos com mais de um buraco podem existir. Inclua suporte no seu algoritmo para não contar bolhas que tocam as bordas da imagem. Não se pode presumir, a priori, que elas tenham buracos ou não.\n\n### SOLUÇÃO\n\nPara retirar as bolhas e buracos que estão nas bordas basta percorrer as bordas da imagem e quando acha um pixel com a cor do objeto usar o ponto como semente no `floodFill` para fazer com que a bolhas tenha a mesma tonalidade do fundo da imagem. Já para conta os buracos, usei uma estrategia de pinta o fundo da imagem de cinza usando o `floodFill` assim, a parte de dentro dos buracos ainda ficaria com a cor do fundo original e eu poderia conta agora quantos buracos tem. Sabendo a quantidade de buracos é só aplicar o `floodFill` na imagem, ver quantos objetos ele encontrou e diminuir do numero de buracos, assim nos temos a quantidade de bolhas e buracos. \n\n![PROCESSAMENTO%20DIGITAL%20DE%20IMAGENS%20-%20EXERCICIOS%202870481b40d7467da90e6c6ee9cd04c5/Untitled%203.png](PROCESSAMENTO%20DIGITAL%20DE%20IMAGENS%20-%20EXERCICIOS%202870481b40d7467da90e6c6ee9cd04c5/Untitled%203.png)\n\n![PROCESSAMENTO%20DIGITAL%20DE%20IMAGENS%20-%20EXERCICIOS%202870481b40d7467da90e6c6ee9cd04c5/Untitled%204.png](PROCESSAMENTO%20DIGITAL%20DE%20IMAGENS%20-%20EXERCICIOS%202870481b40d7467da90e6c6ee9cd04c5/Untitled%204.png)\n\n![PROCESSAMENTO%20DIGITAL%20DE%20IMAGENS%20-%20EXERCICIOS%202870481b40d7467da90e6c6ee9cd04c5/Untitled%205.png](PROCESSAMENTO%20DIGITAL%20DE%20IMAGENS%20-%20EXERCICIOS%202870481b40d7467da90e6c6ee9cd04c5/Untitled%205.png)\n\n![PROCESSAMENTO%20DIGITAL%20DE%20IMAGENS%20-%20EXERCICIOS%202870481b40d7467da90e6c6ee9cd04c5/Untitled%206.png](PROCESSAMENTO%20DIGITAL%20DE%20IMAGENS%20-%20EXERCICIOS%202870481b40d7467da90e6c6ee9cd04c5/Untitled%206.png)\n\n```cpp\n#include \u003ciostream\u003e\n#include \u003copencv2/opencv.hpp\u003e\n\nusing namespace cv;\nusing namespace std;\n\nint main(int argc, char **argv)\n{\n  Mat image, realce;\n  int width, height;\n  int nobjects;\n\n  Point p;\n  image = imread(argv[1], IMREAD_GRAYSCALE);\n\n  if (!image.data)\n  {\n    cout \u003c\u003c \"imagem nao carregou corretamente\\n\";\n    return (-1);\n  }\n\n  width = image.cols;\n  height = image.rows;\n\n  p.x = 0;\n  p.y = 0;\n\n  //excluindo objetos que tocam nas bordas superiores e inferiores\n  for (int i = 0; i \u003c height; i++)\n  {\n    if (image.at\u003cuchar\u003e(0,i) == 255)\n    {\n      p.x = i;\n      p.y = 0;\n      floodFill(image, p,0);\n    }\n    if (image.at\u003cuchar\u003e(width-1,i) == 255)\n    {\n      p.x = i;\n      p.y = width-1;\n      floodFill(image, p,0);\n    }\n  }\n\n  //excluindo objetos que tocam nas bordas laterais\n  for (int i = 0; i \u003c width; i++)\n  {\n    if (image.at\u003cuchar\u003e(i,0) == 255)\n    {\n      p.x = 0;\n      p.y = i;\n      floodFill(image, p,0);\n    }\n    if (image.at\u003cuchar\u003e(i,height-1) == 255)\n    {\n      p.x = height-1;\n      p.y = i;\n      floodFill(image, p,0);\n    }\n  }\n\n  imshow(\"objetos da bordas removidos\", image);\n\n  //mudando a cor do backgrpund para pode identificar os buraco\n  p.x=0;\n  p.y=0;\n  floodFill(image,p,100);\n  imshow(\"bolhas\", image);\n\n  // contando bolhas\n  int buracos = 0;\n  for (int i = 0; i \u003c height; i++)\n  {\n    for (int j = 0; j \u003c width; j++)\n    {\n      if (image.at\u003cuchar\u003e(i, j) == 0)\n      {\n        // achou um objeto\n        buracos++;\n        p.x = j;\n        p.y = i;\n        // preenche o objeto com o contador\n        floodFill(image, p, 255);\n      }\n    }\n  }\n  cout\u003c\u003c\"numero de buracos: \"\u003c\u003cburacos\u003c\u003cendl;\n\n  //rotulando todos os objetos\n  nobjects = 0;\n  for (int i = 0; i \u003c height; i++)\n  {\n    for (int j = 0; j \u003c width; j++)\n    {\n      if (image.at\u003cuchar\u003e(i, j) == 255)\n      {\n        // achou um objeto\n        nobjects++;\n        p.x = j;\n        p.y = i;\n        // preenche o objeto com o contador\n        floodFill(image, p, nobjects);\n      }\n    }\n  }\n\n  cout\u003c\u003c\"numero de bolhas: \"\u003c\u003cnobjects-buracos\u003c\u003cendl;\n\n  imshow(\"labeling\", image);\n  imwrite(\"labeling.png\", image);\n  waitKey();\n  return 0;\n}\n```\n\n---\n\n# MANIPULAÇÃO DE HISTOGRAMAS\n\n### EXERCÍCO 3.1\n\nUtilizando o programa [exemplos/histogram.cpp](https://agostinhobritojr.github.io/tutorial/pdi/exemplos/histogram.cpp) como referência, implemente um programa `equalize.cpp`. Este deverá, para cada imagem capturada, realizar a equalização do histogram antes de exibir a imagem. Teste sua implementação apontando a câmera para ambientes com iluminações variadas e observando o efeito gerado. Assuma que as imagens processadas serão em tons de cinza. \n\n### SOLUÇÃO\n\nPara simular uma entrada em tons de cinza tive que para cinza usando a função `cvtColor`. Para fazer a equalização do histograma utiizei a função `equalizeHist`, logo depois fiz propriamente dito o hitrograma da imagem original e da equalizada, assim tendo uma comparação entre as duas. \n\n![PROCESSAMENTO%20DIGITAL%20DE%20IMAGENS%20-%20EXERCICIOS%202870481b40d7467da90e6c6ee9cd04c5/ezgif.com-gif-maker.gif](PROCESSAMENTO%20DIGITAL%20DE%20IMAGENS%20-%20EXERCICIOS%202870481b40d7467da90e6c6ee9cd04c5/ezgif.com-gif-maker.gif)\n\n```cpp\n#include \u003ciostream\u003e\n#include \u003copencv2/opencv.hpp\u003e\n\nusing namespace cv;\nusing namespace std;\n\nint main(int argc, char** argv){\n  Mat image, icinza, iequalizado;\n  VideoCapture cap;\n  vector\u003cMat\u003e planes;\n  Mat histcinza, histequalizado;\n  int nbins = 64;\n  float range[] = {0, 255};\n  const float *histrange = { range };\n  bool uniform = true;\n  bool acummulate = false;\n  int key;\n\n\tcap.open(0);\n\n  if(!cap.isOpened()){\n    std::cout \u003c\u003c \"cameras indisponiveis\";\n    return -1;\n  }\n\n  cap.set(CAP_PROP_FRAME_WIDTH, 640);\n  cap.set(CAP_PROP_FRAME_HEIGHT, 480);\n\n  int histw = nbins, histh = nbins/2;\n  Mat histImgcinza(histh, histw, CV_8UC1,Scalar(0));\n  Mat histImgequalizado(histh, histw, CV_8UC1,Scalar(0)); \n\n  while(1){\n    cap \u003e\u003e image;\n    \n    //Convertendo para cinza\n    cvtColor(image,icinza,CV_BGR2GRAY);\n\n    //equalizando histograma\n    equalizeHist(icinza,iequalizado);\n\n    //calculando histograma imagem cinza original\n    calcHist(\u0026icinza, 1, 0,Mat(), histcinza, 1,\n                 \u0026nbins, \u0026histrange,\n                 uniform, acummulate);\n    // calculando histograma da imagem cinza equalizada\n    calcHist(\u0026iequalizado, 1, 0,Mat(),histequalizado, 1,\n                 \u0026nbins, \u0026histrange,\n                 uniform, acummulate);\n  \n    //normalizando\n    normalize(histcinza,histcinza, 0,histImgcinza.rows,NORM_MINMAX, -1,Mat());\n    normalize(histequalizado,histequalizado, 0, histImgequalizado.rows,NORM_MINMAX, -1,Mat());\n\n    histImgcinza.setTo(Scalar(0));\n    histImgequalizado.setTo(Scalar(0));\n\n    for(int i=0; i\u003cnbins; i++){\n      line(histImgcinza,\n               Point(i, histh),\n               Point(i, histh-cvRound(histcinza.at\u003cfloat\u003e(i))),\n               Scalar(255, 255, 255), 1, 8, 0);\n      line(histImgequalizado,\n               Point(i, histh),\n               Point(i, histh-cvRound(histequalizado.at\u003cfloat\u003e(i))),\n               Scalar(255, 255, 255), 1, 8, 0);\n    }\n\n    histImgcinza.copyTo(icinza(Rect(0,0,nbins, histh)));\n    histImgequalizado.copyTo(iequalizado(Rect(0,0,nbins, histh)));\n    \n    imshow(\"image cinza\", icinza);\n    imshow(\"image cinza euqalizada\", iequalizado);\n    key = waitKey(30);\n    if(key == 27) break;\n  }\n  return 0;\n}\n```\n\n### EXERCÍCIO 3.2\n\nUtilizando o programa [exemplos/histogram.cpp](https://agostinhobritojr.github.io/tutorial/pdi/exemplos/histogram.cpp) como referência, implemente um programa `motiondetector.cpp`. Este deverá continuamente calcular o histograma da imagem (apenas uma componente de cor é suficiente) e compará-lo com o último histograma calculado. Quando a diferença entre estes ultrapassar um limiar pré-estabelecido, ative um alarme. Utilize uma função de comparação que julgar conveniente. \n\n### SOLUÇÃO\n\nPara solucionar esse exercício tiver que criar um histograma que ficasse sempre salvando o ultimo histograma do ultimo frame e comparando com o histograma mais recente. Para fazer a comparação dos histogramas utilizei a função `compareHis` que me devolve a correlação entre os histogramas, assim consigo criar um `if` e verificar se esse correlação é alta ou baixar e criar um alerta em verde no canto inferior da tela, avisando que teve movimento.\n\n![PROCESSAMENTO%20DIGITAL%20DE%20IMAGENS%20-%20EXERCICIOS%202870481b40d7467da90e6c6ee9cd04c5/ezgif.com-gif-maker_(1).gif](PROCESSAMENTO%20DIGITAL%20DE%20IMAGENS%20-%20EXERCICIOS%202870481b40d7467da90e6c6ee9cd04c5/ezgif.com-gif-maker_(1).gif)\n\n```cpp\n#include \u003ciostream\u003e\n#include \u003copencv2/opencv.hpp\u003e\n\nusing namespace cv;\nusing namespace std;\n\nint main(int argc, char **argv)\n{\n  Mat image;\n  VideoCapture cap;\n  vector\u003cMat\u003e rgb;\n  Mat histR, histanterior;\n  int nbins = 64;\n  float range[] = {0, 255};\n  const float *histrange = {range};\n  bool uniform = true;\n  bool acummulate = false;\n  int key;\n\n  cap.open(0);\n\n  if (!cap.isOpened())\n  {\n    std::cout \u003c\u003c \"cameras indisponiveis\";\n    return -1;\n  }\n\n  cap.set(CAP_PROP_FRAME_WIDTH, 640);\n  cap.set(CAP_PROP_FRAME_HEIGHT, 480);\n\n  int histw = nbins, histh = nbins / 2;\n  Mat histImgR(histh, histw, CV_8UC3, Scalar(0,0,0));\n\n  cap \u003e\u003e image;\n\n  split(image, rgb);\n\n  //calculando histograma imagem do canal vermelho\n  calcHist(\u0026rgb[0], 1, 0, Mat(), histR, 1,\n           \u0026nbins, \u0026histrange,\n           uniform, acummulate);\n\n  //normalizando\n  normalize(histR, histR, 0, histImgR.rows, NORM_MINMAX, -1, Mat());\n\n  while (1)\n  {\n    histR.copyTo(histanterior);\n\n    cap \u003e\u003e image;\n\n    split(image, rgb);\n\n    //calculando histograma imagem do canal vermelho\n    calcHist(\u0026rgb[0], 1, 0, Mat(), histR, 1,\n             \u0026nbins, \u0026histrange,\n             uniform, acummulate);\n\n    //normalizando\n    normalize(histR, histR, 0, histImgR.rows, NORM_MINMAX, -1, Mat());\n\n    histImgR.setTo(Scalar(0));\n\n    double correlacao = compareHist(histR, histanterior,CV_COMP_CORREL);\n\n    if(correlacao \u003c 0.99){\n      circle(image, Point(image.cols - 50, image.rows-50), 20, Scalar(0, 255, 0), CV_FILLED);\n    }\n\n    for(int i=0; i\u003cnbins; i++){\n      line(histImgR,\n               Point(i, histh),\n               Point(i, histh-cvRound(histR.at\u003cfloat\u003e(i))),\n               Scalar(255, 255, 255), 1, 8, 0);\n    }\n    histImgR.copyTo(image(Rect(0,0,nbins, histh)));\n\n    imshow(\"imagem\", image);\n    key = waitKey(30);\n    if (key == 27)\n      break;\n  }\n  return 0;\n}\n```\n\n---\n\n### EXERCÍCIO 4\n\nUtilizando o programa [exemplos/filtroespacial.cpp](https://agostinhobritojr.github.io/tutorial/pdi/exemplos/filtroespacial.cpp) como referência, implemente um programa `laplgauss.cpp`. O programa deverá acrescentar mais uma funcionalidade ao exemplo fornecido, permitindo que seja calculado o laplaciano do gaussiano das imagens capturadas. Compare o resultado desse filtro com a simples aplicação do filtro laplaciano.\n\n### SOLUÇÃO\n\nPara solucionar foi simples, foi somente adicionar a mascara do laplaciano do gaussiano junto as mascaras dos outros filtro e colocar a opção de escolher digitando a tecla `p`. Analisando o filtro laplaciano com o laplaciano do gaussiano percebi-se uma acentuação dos contornos, deixando a linda mais espessa e também mais contornos visíveis. No vídeo foi primeiro aplicado o filtro laplaciano e depois o filtro laplaciano do gaussiano.\n\n![PROCESSAMENTO%20DIGITAL%20DE%20IMAGENS%20-%20EXERCICIOS%202870481b40d7467da90e6c6ee9cd04c5/ezgif.com-gif-maker%201.gif](PROCESSAMENTO%20DIGITAL%20DE%20IMAGENS%20-%20EXERCICIOS%202870481b40d7467da90e6c6ee9cd04c5/ezgif.com-gif-maker%201.gif)\n\n```cpp\n#include \u003ciostream\u003e\n#include \u003copencv2/opencv.hpp\u003e\n\nvoid printmask(cv::Mat \u0026m) {\n  for (int i = 0; i \u003c m.size().height; i++) {\n    for (int j = 0; j \u003c m.size().width; j++) {\n      std::cout \u003c\u003c m.at\u003cfloat\u003e(i, j) \u003c\u003c \",\";\n    }\n    std::cout \u003c\u003c \"\\n\";\n  }\n}\n\nint main(int, char **) {\n  cv::VideoCapture cap;  // open the default camera\n  float media[] = {0.1111, 0.1111, 0.1111, 0.1111, 0.1111,\n                   0.1111, 0.1111, 0.1111, 0.1111};\n  float gauss[] = {0.0625, 0.125,  0.0625, 0.125, 0.25,\n                   0.125,  0.0625, 0.125,  0.0625};\n  float horizontal[] = {-1, 0, 1, -2, 0, 2, -1, 0, 1};\n  float vertical[] = {-1, -2, -1, 0, 0, 0, 1, 2, 1};\n  float laplacian[] = {0, -1, 0, -1, 4, -1, 0, -1, 0};\n  float boost[] = {0, -1, 0, -1, 5.2, -1, 0, -1, 0};\n  float laplgauss [] ={0,0,-1,0,0,0,-1,-2,-1,0,-1,-2,16,-2,-1,\n                      0,-1,-2,-1,0,0,0,-1,0,0};\n\n  cv::Mat frame, framegray, frame32f, frameFiltered;\n  cv::Mat mask(3, 3, CV_32F), mask_scale;\n  cv::Mat result;\n  double width, height;\n  int absolut;\n  char key;\n\n  cap.open(0);\n\n  if (!cap.isOpened())  // check if we succeeded\n    return -1;\n\n  cap.set(cv::CAP_PROP_FRAME_WIDTH, 640);\n  cap.set(cv::CAP_PROP_FRAME_HEIGHT, 480);\n  width = cap.get(cv::CAP_PROP_FRAME_WIDTH);\n  height = cap.get(cv::CAP_PROP_FRAME_HEIGHT);\n  std::cout \u003c\u003c \"largura=\" \u003c\u003c width \u003c\u003c \"\\n\";\n  ;\n  std::cout \u003c\u003c \"altura =\" \u003c\u003c height \u003c\u003c \"\\n\";\n  ;\n  std::cout \u003c\u003c \"fps    =\" \u003c\u003c cap.get(cv::CAP_PROP_FPS) \u003c\u003c \"\\n\";\n  std::cout \u003c\u003c \"format =\" \u003c\u003c cap.get(cv::CAP_PROP_FORMAT) \u003c\u003c \"\\n\";\n\n  cv::namedWindow(\"filtroespacial\", cv::WINDOW_NORMAL);\n  cv::namedWindow(\"original\", cv::WINDOW_NORMAL);\n\n  mask = cv::Mat(3, 3, CV_32F, media);\n  absolut = 1;  // calcs abs of the image\n\n  for (;;) {\n    cap \u003e\u003e frame;  // get a new frame from camera\n    cv::cvtColor(frame, framegray, cv::COLOR_BGR2GRAY);\n    cv::flip(framegray, framegray, 1);\n    cv::imshow(\"original\", framegray);\n    framegray.convertTo(frame32f, CV_32F);\n    cv::filter2D(frame32f, frameFiltered, frame32f.depth(), mask,\n                 cv::Point(1, 1), 0);\n    if (absolut) {\n      frameFiltered = cv::abs(frameFiltered);\n    }\n\n    frameFiltered.convertTo(result, CV_8U);\n\n    cv::imshow(\"filtroespacial\", result);\n\n    key = (char)cv::waitKey(10);\n    if (key == 27) break;  // esc pressed!\n    switch (key) {\n      case 'a':\n        absolut = !absolut;\n        break;\n      case 'm':\n        mask = cv::Mat(3, 3, CV_32F, media);\n        printmask(mask);\n        break;\n      case 'g':\n        mask = cv::Mat(3, 3, CV_32F, gauss);\n        printmask(mask);\n        break;\n      case 'h':\n        mask = cv::Mat(3, 3, CV_32F, horizontal);\n        printmask(mask);\n        break;\n      case 'v':\n        mask = cv::Mat(3, 3, CV_32F, vertical);\n        printmask(mask);\n        break;\n      case 'l':\n        mask = cv::Mat(3, 3, CV_32F, laplacian);\n        printmask(mask);\n        break;\n        case 'p':\n        mask = cv::Mat(5, 5, CV_32F, laplgauss);\n        printmask(mask);\n        break;\n      case 'b':\n        mask = cv::Mat(3, 3, CV_32F, boost);\n        break;\n      default:\n        break;\n    }\n  }\n  return 0;\n}\n```\n\n---\n\n# SEGUNDA UNIDADE\n\n# FILTRAGEM NO DOMÍNIO DA FREQUÊNCIA\n\n### EXERCÍCIO 7\n\nUtilizando o programa [exemplos/dft.cpp](https://agostinhobritojr.github.io/tutorial/pdi/exemplos/dft.cpp) como referência, implemente o filtro homomórfico para melhorar imagens com iluminação irregular. Crie uma cena mal iluminada e ajuste os parâmetros do filtro homomórfico para corrigir a iluminação da melhor forma possível. Assuma que a imagem fornecida é em tons de cinza.\n\n### SOLUÇÃO\n\nUsando o programa `dft.cpp` como exemplo criei uma função `filtro` para implementar o filtro homomórfico que se da com essa equação:\n\n![Untitled](PROCESSAMENTO%20DIGITAL%20DE%20IMAGENS%20-%20EXERCICIOS%202870481b40d7467da90e6c6ee9cd04c5/Untitled%207.png)\n\nAinda dentro da função do filtro, utilizei o código de plotar o espectro do exemplo para plota o espectro do filtro e assim poder ajusta-lo melhor baseado em seu espectro. \n\nO filtro precisa que seus parâmetros sejam ajustados conforme a cena, sendo assim criei, barras deslizantes com seus parâmetros: `yl` , `yh` , `d0` e `c` .\n\nAproveitei também do código exemplo a função `deslocaDFT` para poder trabalhar melhor com o filtro e o espectro. \n\n![ezgif.com-gif-maker(1).gif](PROCESSAMENTO%20DIGITAL%20DE%20IMAGENS%20-%20EXERCICIOS%202870481b40d7467da90e6c6ee9cd04c5/ezgif.com-gif-maker(1).gif)\n\n```cpp\n#include \u003ciostream\u003e\n#include \u003copencv2/opencv.hpp\u003e\n#include \u003cvector\u003e\n\nusing namespace std;\nusing namespace cv;\n\nMat complexImage;\nMat padded, filter;\nMat image, imagegray, magI;\nMat_\u003cfloat\u003e realInput, zeros, ones;\nvector\u003cMat\u003e planos;\n\nfloat yl = 0, yh = 0, d0 = 0, c = 0;\nfloat ylmax = 100, yhmax = 100, d0max = 256, cmax = 100;\nint yl_slider = 1, yh_slider = 1, d0_slider = 1, c_slider = 1;\n\n//para calculo da DFT\nint dft_M, dft_N;\n\n// troca os quadrantes da imagem da DFT\nvoid deslocaDFT(Mat\u0026 image) {\n  Mat tmp, A, B, C, D;\n\n  // se a imagem tiver tamanho impar, recorta a regiao para\n  // evitar cópias de tamanho desigual\n  image = image(Rect(0, 0, image.cols \u0026 -2, image.rows \u0026 -2));\n  int cx = image.cols / 2;\n  int cy = image.rows / 2;\n\n  // reorganiza os quadrantes da transformada\n  // A B   -\u003e  D C\n  // C D       B A\n  A = image(Rect(0, 0, cx, cy));\n  B = image(Rect(cx, 0, cx, cy));\n  C = image(Rect(0, cy, cx, cy));\n  D = image(Rect(cx, cy, cx, cy));\n\n  // A \u003c-\u003e D\n  A.copyTo(tmp);\n  D.copyTo(A);\n  tmp.copyTo(D);\n\n  // C \u003c-\u003e B\n  C.copyTo(tmp);\n  B.copyTo(C);\n  tmp.copyTo(B);\n}\n\nvoid filtro(){\n  Mat filter = Mat(padded.size(), CV_32FC2, Scalar(0));\n  Mat tmp = Mat(dft_M, dft_N, CV_32F);\n  float d2, exp, filtroH;\n  for (int i = 0; i \u003c dft_M; i++) {\n      for (int j = 0; j \u003c dft_N; j++) {\n          d2 = pow(i - dft_M/2.0, 2) + pow(j - dft_N/2.0, 2);\n          exp = - c*(d2/pow(d0, 2));\n          filtroH = (yh - yl)*(1 - expf(exp) ) + yl;\n          tmp.at\u003cfloat\u003e (i,j) = filtroH;\n      }\n  }\n\n  Mat comps[] = {tmp, tmp};\n  merge(comps, 2, filter);\n\n  Mat dftClone = complexImage.clone();\n\n  mulSpectrums(dftClone,filter,dftClone,0);\n\n  // exibe o espectro \n  planos.clear();\n  split(filter, planos);\n\n  Mat magn, angl, anglInt, magnInt;\n\n  magnitude(planos[0], planos[1], planos[0]);\n  magI = planos[0];\n  magI += Scalar::all(1);\n  log(magI, magI);\n  normalize(magI, magI, 0, 255, NORM_MINMAX);\n  magI.convertTo(magnInt, CV_8U);\n  imshow(\"Espectro\", magnInt);\n\n  deslocaDFT(dftClone);\n\n  idft(dftClone, dftClone);\n\n  split (dftClone, planos);\n\n  normalize(planos[0], planos[0], 0, 1, CV_MINMAX);\n\n  imshow(\"Filtro Homomorfico\", planos[0]);\n}\n\nvoid on_trackbar_yl(int, void*){\n    yl = (float) yl_slider;\n    yl = ylmax*yl/100.0;\n    filtro();\n}\n\nvoid on_trackbar_d0(int, void*){\n    d0 = d0_slider*d0max/100.0;\n    filtro();\n}\n\nvoid on_trackbar_yh(int, void*) {\n    yh = yh_slider*yhmax/100.0;\n    filtro();\n}\nvoid on_trackbar_c(int, void*) {\n    c = c_slider*cmax / 100.0;\n    filtro();\n}\n\nint main() {\n\n  VideoCapture cap;\n\n  // guarda tecla capturada\n  char key;\n\n  // abre a câmera\n  cap.open(0);\n  if (!cap.isOpened()){\n    return -1;\n  } \n\n  cap.set(CAP_PROP_FRAME_WIDTH, 640);\n  cap.set(CAP_PROP_FRAME_HEIGHT, 480);\n\n  // captura uma imagem para recuperar as\n  // informacoes de gravação\n  cap \u003e\u003e image;\n\n  // identifica os tamanhos otimos para\n  // calculo do FFT\n  dft_M = getOptimalDFTSize(image.rows);\n  dft_N = getOptimalDFTSize(image.cols);\n\n  // realiza o padding da imagem\n  copyMakeBorder(image, padded, 0, dft_M - image.rows, 0,\n                     dft_N - image.cols,BORDER_CONSTANT,\n                     Scalar::all(0));\n\n  // parte imaginaria da matriz complexa (preenchida com zeros)\n  zeros = Mat_\u003cfloat\u003e::zeros(padded.size());\n  ones = Mat_\u003cfloat\u003e::zeros(padded.size());\n\n  // prepara a matriz complexa para ser preenchida\n  complexImage = Mat(padded.size(), CV_32FC2,Scalar(0));\n\n  // a função de transferencia (filtro de frequencia) deve ter o\n  // mesmo tamanho e tipo da matriz complexa\n  filter = complexImage.clone();\n\n  namedWindow(\"original\", 0);\n  namedWindow(\"Filtro Homomorfico\", 1);\n\n  /* Cria as barras de rolagem com todos os parâmetros. */\n    createTrackbar( \"YH\", \"Filtro Homomorfico\",\n                  \u0026yh_slider,\n                  100.0,\n                  on_trackbar_yh);\n    on_trackbar_yh(yh_slider,0);\n\n    createTrackbar( \"YL\", \"Filtro Homomorfico\",\n                  \u0026yl_slider,\n                  100.0,\n                  on_trackbar_yl);\n    on_trackbar_yl(yl_slider,0);\n\n    createTrackbar( \"D0\", \"Filtro Homomorfico\",\n                  \u0026d0_slider,\n                  100.0,\n                  on_trackbar_d0 );\n    on_trackbar_d0(d0_slider,0);\n\n    createTrackbar( \"C\", \"Filtro Homomorfico\",\n                  \u0026c_slider,\n                  100.0,\n                  on_trackbar_c);\n    on_trackbar_c(c_slider,0);\n\n  for(;;){\n    //namedWindow(\"original\", 0);\n    cap \u003e\u003e image;  // get a new frame from camera\n    cvtColor(image, imagegray, COLOR_BGR2GRAY);\n    flip(imagegray, imagegray, 1);\n    imshow(\"original\", imagegray);\n\n    // realiza o padding da imagem\n    copyMakeBorder(imagegray, padded, 0, dft_M - image.rows, 0,\n                       dft_N - image.cols, BORDER_CONSTANT,\n                       Scalar::all(0));\n\n    // limpa o array de matrizes que vao compor a\n    // imagem complexa\n    planos.clear();\n    // cria a compoente real\n    realInput = Mat_\u003cfloat\u003e(padded);\n    // insere as duas componentes no array de matrizes\n    planos.push_back(realInput);\n    planos.push_back(zeros);\n\n    // combina o array de matrizes em uma unica\n    // componente complexa\n    merge(planos, complexImage);\n\n    // calcula o dft\n    dft(complexImage, complexImage);\n    // realiza a troca de quadrantes\n    deslocaDFT(complexImage);\n\n    filtro();\n\n    key = (char) waitKey(10);\n    if (key == 27) break;\n\n  }\n \n  return 0;\n}\n```\n\n---\n\n# DETECÇÃO DE BORDAS COM O ALGORITMO DE CANNY E PONTILHISMO\n\n### EXERCÍCIO 8\n\nUtilizando os programas [exemplos/canny.cpp](https://agostinhobritojr.github.io/tutorial/pdi/exemplos/canny.cpp) e [exemplos/pontilhismo.cpp](https://agostinhobritojr.github.io/tutorial/pdi/exemplos/pontilhismo.cpp) como referência, implemente um programa `cannypoints.cpp`. A ideia é usar as bordas produzidas pelo algoritmo de Canny para melhorar a qualidade da imagem pontilhista gerada. A forma como a informação de borda será usada é livre. Entretanto, são apresentadas algumas sugestões de técnicas que poderiam ser utilizadas:\n\n- Desenhar pontos grandes na imagem pontilhista básica;\n- Usar a posição dos pixels de borda encontrados pelo algoritmo de Canny para desenhar pontos nos respectivos locais na imagem gerada.\n- Experimente ir aumentando os limiares do algoritmo de Canny e, para cada novo par de limiares, desenhar círculos cada vez menores nas posições encontradas.\n- Escolha uma imagem de seu gosto e aplique a técnica que você\ndesenvolveu.\n- Descreva no seu relatório detalhes do procedimento usado para criar\nsua técnica pontilhista.\n\n### SOLUÇÃO\n\nUtilizando os códigos dos exemplos juntei as duas funcionalidades. Para isso peguei os parâmetros fixos do código do pontilhismo transformei em inteiros para poder fazer deles barras deslizantes. \n\nApós isso peguei o código para formação do pontilhismo e criei uma função `pontilhismo` e dentro dela modifiquei o `for` para só aplicar o pontilhismo desejado quando o pixel comparado com o pixel da matriz  `border` gerada pela função `canny` fosse `= 255` , e se não fosse eu ainda aplicaria o pontilhismo mais com o `raio` fixo em `2`. Para a função canny eu utilizo exatamente o código exemplo.\n\n![ezgif.com-gif-maker.gif](PROCESSAMENTO%20DIGITAL%20DE%20IMAGENS%20-%20EXERCICIOS%202870481b40d7467da90e6c6ee9cd04c5/ezgif.com-gif-maker%202.gif)\n\n```cpp\n#include \u003ciostream\u003e\n#include \u003copencv2/opencv.hpp\u003e\n#include \u003cfstream\u003e\n#include \u003ciomanip\u003e\n#include \u003cvector\u003e\n#include \u003calgorithm\u003e\n#include \u003cnumeric\u003e\n#include \u003cctime\u003e\n#include \u003ccstdlib\u003e\n\nusing namespace std;\nusing namespace cv;\n\nint STEP = 5;\nint JITTER = 3;\nint RAIO = 3;\n\nint top_slider = 10;\nint top_slider_max = 200;\n\nMat image, points,imageGray, border;\n\nvoid pontilhismo(){\n  vector\u003cint\u003e yrange;\n  vector\u003cint\u003e xrange;\n  Vec3b color;\n\n  int width, height;\n  int x, y;\n  \n  width=image.size().width;\n  height=image.size().height;\n\n  xrange.resize(height/STEP);\n  yrange.resize(width/STEP);\n\n  iota(xrange.begin(), xrange.end(), 0);\n  iota(yrange.begin(), yrange.end(), 0);\n\n  for(uint i=0; i\u003cxrange.size(); i++){\n    xrange[i]= xrange[i]*STEP+STEP/2;\n  }\n\n  for(uint i=0; i\u003cyrange.size(); i++){\n    yrange[i]= yrange[i]*STEP+STEP/2;\n  }\n\n  random_shuffle(xrange.begin(), xrange.end());\n\n  for(auto i : xrange){\n    random_shuffle(yrange.begin(), yrange.end());\n    for(auto j : yrange){\n      if (border.at\u003cuchar\u003e(i, j) == 255){\n        x = i+rand()%(2*JITTER)-JITTER+1;\n        y = j+rand()%(2*JITTER)-JITTER+1;\n        color = image.at\u003cVec3b\u003e(x,y);\n        circle(points,\n             Point(y,x),\n             RAIO,\n             CV_RGB(color[2],color[1],color[0]),\n             -1,\n             CV_AA);\n      }\n      else{\n        x = i+rand()%(2*JITTER)-JITTER+1;\n        y = j+rand()%(2*JITTER)-JITTER+1;\n        color = image.at\u003cVec3b\u003e(x,y);\n        circle(points,\n             Point(y,x),\n             2,\n             CV_RGB(color[2],color[1],color[0]),\n             -1,\n             CV_AA);\n\n      }\n      \n    }\n  }\n  imshow(\"cannypoints\", points);\n}\n\nvoid on_trackbar_canny(int, void*){\n  Canny(image, border, top_slider, 3*top_slider);\n  pontilhismo();\n  namedWindow(\"canny\",1);\n  imshow(\"canny\",border);\n}\n\nvoid on_trackbar_cannypoints(int,void*){\n  pontilhismo();\n}\n\nint main(int argc, char** argv){\n  \n  image= imread(argv[1],CV_LOAD_IMAGE_COLOR);\n\n  cvtColor(image, imageGray, CV_BGR2GRAY);\n\n  points = image.clone();\n  border = imageGray.clone();\n\n  srand(time(0));\n\n  if(!image.data){\n\tcout \u003c\u003c \"nao abriu\" \u003c\u003c argv[1] \u003c\u003c endl;\n    cout \u003c\u003c argv[0] \u003c\u003c \" imagem.jpg\";\n    exit(0);\n  }\n  namedWindow(\"cannypoints\",0);\n  createTrackbar(\"Threshold inferior\", \"cannypoints\",\n                \u0026top_slider,\n                top_slider_max,\n                on_trackbar_canny );\n\n  on_trackbar_canny(top_slider, 0 );\n  createTrackbar(\"STEP\", \"cannypoints\",\n                \u0026STEP,\n                100,\n                on_trackbar_cannypoints);\n\n  on_trackbar_cannypoints(STEP,0);\n\n  createTrackbar(\"JITTER\", \"cannypoints\",\n                \u0026JITTER,\n                100,\n                on_trackbar_cannypoints);\n\n  on_trackbar_cannypoints(JITTER,0);\n\n  createTrackbar(\"RAIO\", \"cannypoints\",\n                \u0026RAIO,\n                100,\n                on_trackbar_cannypoints);\n\n  on_trackbar_cannypoints(RAIO,0);\n  \n  waitKey(0);\n  return 0;\n}\n```\n\n---\n\n# QUANTIZAÇÃO VETORIAL COM K-MEANS\n\n### EXERCÍCIO 9\n\nUtilizando o programa [kmeans.cpp](https://agostinhobritojr.github.io/tutorial/pdi/exemplos/kmeans.cpp) como exemplo prepare um programa exemplo onde a execução do código se dê usando o parâmetro `nRodadas=1` e inciar os centros de forma aleatória usando o parâmetro `KMEANS_RANDOM_CENTER` ao invés de `KMEANS_PP_CENTERS`. Realize 10 rodadas diferentes do algoritmo e compare as imagens produzidas. Explique porque elas podem diferir tanto.\n\n### SOLUÇÃO\n\nUtilizando o exemplo modifiquei o parâmetro `KMEANS_PP_CENTERS` para o `KMEANS_RANDOM_CENTERS`     e mudei o numero de rodadas para 1. Logo apos isso para fazer as 10 rodadas diferentes coloquei um `for` englobando todo o código e a cada rodada salvar a foto gerada e por fim mostro a ultima gerada na tela. \n\nPara demostra o resultado transformei 10 fotos em um `gif` para fica mais dinâmico. O motivo da mudança entra uma rodada e outra é por causa da mudança do parâmetro `KMEANS_PP_CENTERS` que faz com que os centros gerados inicialmente sejam aleatórios. A variável `nRodadas` também pode interferir nesse resultado pois o algoritmo é feito uma unica vez e é pego o primeiro resultado \n\n![comida.jpg](PROCESSAMENTO%20DIGITAL%20DE%20IMAGENS%20-%20EXERCICIOS%202870481b40d7467da90e6c6ee9cd04c5/comida.jpg)\n\nI**magem original** \n\n![5ky89f.gif](PROCESSAMENTO%20DIGITAL%20DE%20IMAGENS%20-%20EXERCICIOS%202870481b40d7467da90e6c6ee9cd04c5/5ky89f.gif)\n\n**Gif do resultado do K-means**\n\n```cpp\n#include \u003copencv2/opencv.hpp\u003e\n#include \u003ccstdlib\u003e\n\nusing namespace cv;\n\nint main( int argc, char** argv ){\n  int nClusters = 8;\n  Mat rotulos;\n  int nRodadas = 1;\n  Mat centros;\n  char name[15];\n  Mat img = imread( argv[1], CV_LOAD_IMAGE_COLOR);\n  Mat samples(img.rows * img.cols, 3, CV_32F);\n  Mat rotulada( img.size(), img.type() );\n\n  for (int i=0; i\u003c10; i++){\n  \n    for( int y = 0; y \u003c img.rows; y++ ){\n      for( int x = 0; x \u003c img.cols; x++ ){\n        for( int z = 0; z \u003c 3; z++){\n          samples.at\u003cfloat\u003e(y + x*img.rows, z) = img.at\u003cVec3b\u003e(y,x)[z];\n\t      }\n\t    }\n    }\n\n    kmeans(samples,\n\t\t  nClusters,\n\t\t  rotulos,\n\t\t  TermCriteria(CV_TERMCRIT_ITER|CV_TERMCRIT_EPS, 10000, 0.0001),\n\t\t  nRodadas,\n\t\t  KMEANS_RANDOM_CENTERS,\n\t\t  centros);\n\n    for( int y = 0; y \u003c img.rows; y++ ){\n      for( int x = 0; x \u003c img.cols; x++ ){\n\t      int indice = rotulos.at\u003cint\u003e(y + x*img.rows,0);\n\t      rotulada.at\u003cVec3b\u003e(y,x)[0] = (uchar) centros.at\u003cfloat\u003e(indice, 0);\n\t      rotulada.at\u003cVec3b\u003e(y,x)[1] = (uchar) centros.at\u003cfloat\u003e(indice, 1);\n\t      rotulada.at\u003cVec3b\u003e(y,x)[2] = (uchar) centros.at\u003cfloat\u003e(indice, 2);\n\t    }\n    }\n    sprintf(name,\"k-imagem%d.jpg\",i);\n    imwrite(name, rotulada);\n  }\n    imshow( \"clustered image\", rotulada);\n    waitKey( 0 );\n}\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffrankson18%2Fprocessamento-digital-imagens","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ffrankson18%2Fprocessamento-digital-imagens","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffrankson18%2Fprocessamento-digital-imagens/lists"}