go 图片相似 查找两张图片不同的部分 找出两幅图片中的不同处

golang Image similarity comparison

目前网上找了很多的 图片相似 查找两张图片不同的部分,实现图像比较和标记以显示不同 ,很多都是python写的,没有找到go语言写的,所以想自己写一个

图片A 为参照物,去寻找图片B 的最佳重合位置,然后再查找图片的不同之处。这一步暂时未做,以后如果有时间或者相关需要 再写。 目前图片轮廓相同 未裁剪。 目前设想,可以截取图片A的部分 取匹配到图片B的位置上,然后再对比两个范围内的像素。

 代码未优化 ,需改进。

AverageHash DifferenceHash PerceptionHash 三种常用算法,适合比对相似图片,我们是求差别。这三种算法,作为图片的相似性识别挺好。但是用来找差异,有些处理结果让人费解。

这是方式一  go/ImageDifferenceHash.go at main · shuidaan/go · GitHub

package mainimport ("errors""fmt""github.com/corona10/goimagehash""image""image/color""image/draw""image/jpeg""os""sort""strconv""time"
)
type outline struct {x inty int
}
type Outlinesort []outline
type Outlinesortx []outlinefunc (o Outlinesort) Len() int {//返回传入数据的总数return len(o)
}
func (o Outlinesort) Swap(i, j int) {//两个对象满足Less()则位置对换//表示执行交换数组中下标为i的数据和下标为j的数据o[i], o[j] = o[j], o[i]
}
func (o Outlinesort) Less(i, j int) bool {//按字段比较大小,此处是降序排序//返回数组中下标为i的数据是否小于下标为j的数据return o[i].y < o[j].y
}
func (o Outlinesortx) Len() int {//返回传入数据的总数return len(o)
}
func (o Outlinesortx) Swap(i, j int) {//两个对象满足Less()则位置对换//表示执行交换数组中下标为i的数据和下标为j的数据o[i], o[j] = o[j], o[i]
}
func (o Outlinesortx) Less(i, j int) bool {//按字段比较大小,此处是降序排序//返回数组中下标为i的数据是否小于下标为j的数据return o[i].x < o[j].x
}
func main() {file1, _ := os.Open("E:\\wq\\img\\a0.jpg")file2, _ := os.Open("E:\\wq\\img\\a8.jpg")defer file1.Close()defer file2.Close()img1, _ := jpeg.Decode(file1)img2, _ := jpeg.Decode(file2)width, high := img1.Bounds().Dx(),img1.Bounds().Dy()var status,same, gap, z,h,w int = 0,1,1,0,8,8    //status same划线状态,gap允许色差 z多少个差别  h单个色块高 w单个色块宽var outlines []outline = make([]outline,0,(width+high)/64)b := img1.Bounds()//根据b画布的大小新建一个新图像m := image.NewRGBA(b)draw.Draw(m, b, img1, b.Min, draw.Over)测试被裁剪的小图是否全部加入对比//sb1 := img1.Bounds()根据b画布的大小新建一个新图像//sm1 := image.NewRGBA(sb1)////sb2 := img1.Bounds()根据b画布的大小新建一个新图像//sm2 := image.NewRGBA(sb2)for i:= 0;i < width ; i+=w {for j:=0 ; j < high ; j+=h  {subimg1,err := clip(img1,i,j,w,h)if err != nil {fmt.Println(err)}subimg2,err := clip(img2,i,j,w,h)if err != nil {fmt.Println(err)}//soffet1 := image.Pt(i,j)//ssr1 := subimg2.Bounds()//draw.Draw(sm1,sb1,subimg1,ssr1.Min.Sub(soffet1),draw.Over)//soffet2 := image.Pt(i,j)//ssr2 := subimg2.Bounds()//draw.Draw(sm2,sb2,subimg2,ssr2.Min.Sub(soffet2),draw.Over)hash1, _ := goimagehash.DifferenceHash(subimg1)  //AverageHash  DifferenceHash  PerceptionHash 三种常用算法hash2, _ := goimagehash.DifferenceHash(subimg2)distance, err := hash1.Distance(hash2)if err != nil {fmt.Println(err)}if distance > gap {offet := image.Pt(i,j)sr := subimg2.Bounds()outlines = append(outlines, outline{x:i,y:j,})draw.Draw(m,b,subimg2,sr.Min.Sub(offet),draw.Over)if status == 0 && same == 1 {drawline(i,j,4,2,w,m)status = 1}z++}if  status == 1 &&  distance <= gap {outlines = append(outlines, outline{x:i,y:j,})drawline(i,j,4,3,w,m)status,same = 0, 1}} //w}//hname1 := strconv.Itoa(int(time.Now().Unix()))imgw, err := os.Create(name1 + "shuidaan.jpg")if err != nil {fmt.Println(err)}//测试被裁剪的小图是否全部加入对比//simgw1, err := os.Create(name1 + "new1.jpg")//if err != nil {//	fmt.Println(err)//}//simgw2, err := os.Create(name1 + "new2.jpg")//if err != nil {//	fmt.Println(err)//}//sort.Sort(Outlinesortx(outlines))sort.Sort(Outlinesort(outlines))sortline(outlines)for k,v := range outlines{if k == 0 {status, same= 0,0}if k+1 == len(outlines) {drawline(outlines[k].x,outlines[k].y,4,1,w,m)}if status == 0 && same == 0 {drawline(v.x,v.y,4,0,w,m)same, status = v.x,1continue}if v.x - same == w {same, status= v.x,1}if (v.x - same > w || v.y != outlines[k-1].y ) && status == 1{drawline(outlines[k-1].x,outlines[k-1].y,4,1,w,m)same,status = 0, 0}}jpeg.Encode(imgw, m, &jpeg.Options{100})defer imgw.Close()//	//	测试被裁剪的小图是否全部加入对比//jpeg.Encode(simgw1, sm1, &jpeg.Options{100})//defer simgw1.Close()////jpeg.Encode(simgw2, sm2, &jpeg.Options{100})//defer simgw2.Close()fmt.Println("切片大小 不同图像块 每次对比宽度分别是:", cap(outlines),z,w)
}func clip(src image.Image, x, y, w, h int) (image.Image, error) {var subImg image.Imageif rgbImg, ok := src.(*image.YCbCr); ok {subImg = rgbImg.SubImage(image.Rect(x, y, x+w, y+h)).(*image.YCbCr) //图片裁剪x0 y0 x1 y1} else if rgbImg, ok := src.(*image.RGBA); ok {subImg = rgbImg.SubImage(image.Rect(x, y, x+w, y+h)).(*image.RGBA) //图片裁剪x0 y0 x1 y1} else if rgbImg, ok := src.(*image.NRGBA); ok {subImg = rgbImg.SubImage(image.Rect(x, y, x+w, y+h)).(*image.NRGBA) //图片裁剪x0 y0 x1 y1} else {return subImg, errors.New("图片解码失败")}return subImg, nil
}
func drawline(x, y, size, dire, zone int, m *image.RGBA) error {//x,y划线起点坐标  size线粗  dire线方向 zone对比像素大小size+=4switch dire {case 0:for dot := 4;dot < size;dot++ {for z:= 0;z < zone ;z++  {m.Set(x-dot,y+z,color.RGBA{255, 0, 0, 255})}}case 1:for dot := 4;dot < size;dot++ {for z:= 0;z < zone ;z++  {m.Set(x+dot+zone,y+z,color.RGBA{0, 255, 0, 255})}}case 2:for dot := 4;dot < size;dot++ {for z:= 0;z < zone ;z++  {m.Set(x+z,y-dot,color.RGBA{255, 0, 0, 255})}}case 3:for dot := 4;dot < size;dot++ {for z:= 0;z < zone ;z++  {m.Set(x+z,y+dot,color.RGBA{0, 255, 0, 255})}}default:return errors.New("Parameter error")}return nil
}// 排序,用于框出差异,优化减少重复设置像素  切片指针传递
func sortline(outlines Outlinesort) {oy,startkey := -1,0if len(outlines) > 0 {oy = outlines[0].y}var sortx  Outlinesortfor key,value := range outlines {if value.y != oy {sortx = outlines[startkey:key]sort.Sort(Outlinesortx(sortx))startkey,oy = key,value.y}if key == outlines.Len() {sortx = outlines[startkey:key]sort.Sort(Outlinesortx(sortx))}}
}

方式二

有点简单粗暴,直接逐个对比像素点。前提是要两张大小 轮廓 位置相同的图片。本来是设想对比相片是否相同,是否存在差异,固定架拍摄,因此轮廓相同。  后期考虑做图片位置重合匹配

https://gitee.com/shuidaan/golang/raw/master/ImageDifferencePx.go 源码

package mainimport ("errors""fmt""image""image/color""image/draw""image/jpeg""math""os""sort""strconv""time"
)
type outline struct {x inty int
}
type Outlinesort []outline
type Outlinesortx []outlinefunc (o Outlinesort) Len() int {//返回传入数据的总数return len(o)
}
func (o Outlinesort) Swap(i, j int) {//两个对象满足Less()则位置对换//表示执行交换数组中下标为i的数据和下标为j的数据o[i], o[j] = o[j], o[i]
}
func (o Outlinesort) Less(i, j int) bool {//按字段比较大小,此处是降序排序//返回数组中下标为i的数据是否小于下标为j的数据return o[i].y < o[j].y
}
func (o Outlinesortx) Len() int {//返回传入数据的总数return len(o)
}
func (o Outlinesortx) Swap(i, j int) {//两个对象满足Less()则位置对换//表示执行交换数组中下标为i的数据和下标为j的数据o[i], o[j] = o[j], o[i]
}
func (o Outlinesortx) Less(i, j int) bool {//按字段比较大小,此处是降序排序//返回数组中下标为i的数据是否小于下标为j的数据return o[i].x < o[j].x
}
func main() {t2 := time.Now().Nanosecond()file1, _ := os.Open(".\\img\\a0.jpg")file2, _ := os.Open(".\\img\\a8.jpg")defer file1.Close()defer file2.Close()img1, _ := jpeg.Decode(file1)img2, _ := jpeg.Decode(file2)width, high := img1.Bounds().Dx(),img1.Bounds().Dy()var status,same, z,h,w int = 0,1,0,1,1   //status same划线状态,gap允许色差 z多少个差别  h单个色块高 w单个色块宽var gap float64 = 1var outlines []outline = make([]outline,0,(width*high)/32)b := img1.Bounds()//根据b画布的大小新建一个新图像m := image.NewRGBA(b)draw.Draw(m, b, img1, b.Min, draw.Over)for i:= 0;i < width ; i+=w {for j:=0 ; j < high ; j+=h  {subimg1px := rgb2gray1px(img1.At(i,j))subimg2px := rgb2gray1px(img2.At(i,j))//AverageHash  DifferenceHash  PerceptionHash 三种常用算法,适合比对相似图片。我们是求差别distance := math.Abs(subimg1px - subimg2px)if distance > gap {z++outlines = append(outlines, outline{x:i,y:j,})if status == 0 && same == 1 {//outlines = append(outlines, outline{//	x:i,//	y:j,//})drawline(i,j,4,2,w,m)	//竖向画框status = 1}}if  status == 1 &&  distance <= gap {outlines = append(outlines, outline{x:i,y:j,})drawline(i,j,4,3,w,m)	//竖向画框status,same = 0, 1}} //w}//hname1 := strconv.Itoa(int(time.Now().Unix()))imgw, err := os.Create(name1 + "shuidaan.jpg")if err != nil {fmt.Println(err)}sort.Sort(Outlinesort(outlines))sortline(outlines)for k,v := range outlines{if k == 0 {status, same= 0,0}if k+1 == len(outlines) {drawline(outlines[k].x,outlines[k].y,4,1,w,m)}if status == 0 && same == 0 {drawline(v.x,v.y,4,0,w,m)same, status = v.x,1continue}if v.x - same == w {same, status= v.x,1}if (v.x - same > w || v.y != outlines[k-1].y ) && status == 1{drawline(outlines[k-1].x,outlines[k-1].y,4,1,w,m)same,status = 0, 0}}for _,v := range outlines{m.Set(v.x,v.y,img2.At(v.x,v.y))}jpeg.Encode(imgw, m, &jpeg.Options{100})defer imgw.Close()t3:= time.Now().Nanosecond() -t2fmt.Printf("This picture width is %d,height is %d pixels. The program runs for %d milliseconds. There are %d pixels that are different \n",width,high,t3/1e6,len(outlines))fmt.Printf("图片宽 %d,高 %d 像素. 程序运行耗时 %d 毫秒. 相片有 %d 像素不同 \n",width,high,t3/1e6,len(outlines))
}//由点划线
func drawline(x, y, size, dire, zone int, m *image.RGBA) error {//x,y划线起点坐标  size线粗  dire线方向 zone对比像素大小size+=4switch dire {case 0:for dot := 4;dot < size;dot++ {for z:= 0;z < zone ;z++  {m.Set(x-dot,y+z,color.RGBA{255, 0, 0, 255})}}case 1:for dot := 4;dot < size;dot++ {for z:= 0;z < zone ;z++  {m.Set(x+dot+zone,y+z,color.RGBA{0, 255, 0, 255})}}case 2:for dot := 4;dot < size;dot++ {for z:= 0;z < zone ;z++  {m.Set(x+z,y-dot,color.RGBA{255, 0, 0, 255})}}case 3:for dot := 4;dot < size;dot++ {for z:= 0;z < zone ;z++  {m.Set(x+z,y+dot,color.RGBA{0, 255, 0, 255})}}default:return errors.New("Parameter error")}return nil
}// 排序,用于框出差异,优化减少重复设置像素  切片指针传递
func sortline(outlines Outlinesort) {oy,startkey := -1,0if len(outlines) > 0 {oy = outlines[0].y}var sortx  Outlinesortfor key,value := range outlines {if value.y != oy {sortx = outlines[startkey:key]sort.Sort(Outlinesortx(sortx))startkey,oy = key,value.y}if key == outlines.Len() {sortx = outlines[startkey:key]sort.Sort(Outlinesortx(sortx))}}
}
//将rgb像素转化为gray,用于对比色差
func rgb2gray1px(colorImg color.Color) float64 {r, g, b, _ := colorImg.RGBA()lum := 0.299*float64(r/257) + 0.587*float64(g/257) + 0.114*float64(b/256)return lum
}

代码未优化  需改进

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/48478.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

元宇宙是个什么样的概念?

什么是元宇宙&#xff1f; 百度百科上提到&#xff1a; 元宇宙&#xff08;Metaverse&#xff09;&#xff0c;是人类运用数字技术构建的&#xff0c;由现实世界映射或超越现实世界&#xff0c;可与现实世界交互的虚拟世界&#xff0c;具备新型社会体系的数字生活空间。 元宇…

最全元宇宙概念分析!元宇宙为何发展于区块链?

元宇宙&#xff0c;Web3 时代最新热词&#xff0c;和 NFT、DAO 等新晋热门概念一起在 2021 年横空出世。这一概念最早诞生于 1992 年的科幻小说《雪崩》&#xff0c;小说中描绘了一个庞大的虚拟现实世界&#xff0c;人们用数字化身来控制&#xff0c;并相互竞争以提高自己的地位…

chatgpt赋能python:Python期末考:如何顺利通过?

Python期末考&#xff1a;如何顺利通过&#xff1f; Python是一门广受欢迎的编程语言&#xff0c;无论是初学者还是有经验的工程师&#xff0c;都会在其职业生涯中使用Python。在学术领域&#xff0c;Python也被广泛应用于数据分析、人工智能和机器学习等方面。但是&#xff0…

【电商系列】shopee的数据获取

在Amazon&#xff0c;Aliexpress之后&#xff0c;又一个海外电商出现在我的视野里——shopee&#xff0c;在东南亚很火的电商平台。 这战略布局都到南美跟欧洲了 这网站有意思的是啊&#xff0c;每个国家的商品虽然大同小异&#xff0c;但是也能凸显各个国家的风格的&#xff0…

分享4点选品思路,电商大牛都在用

Tiktok选品数据分析是很多跨境电商商家都需要解决的首要问题。如何选品才能提高TikTok变现率&#xff1f;商家选品时需要结合实际数据进行分析&#xff0c;不能一概而论。本文将和大家谈论三个问题。 选品思路 选品方法 选品数据哪里找&#xff1f; 一、选品思路 选品是tiktok小…

电商平台OnBuy选品技巧分享一二

OnBuy是这两年发展较快的蓝海电商平台&#xff0c;是跨境电商人可以选择的一个优质电商平台。今天我们小编就给大家分享一下OnBuy选品技巧以及方法&#xff0c;希望对大家有用。 OnBuy热销类目 1、 健康(防护用品) 2、 美妆护肤 3、 多媒体 4、 玩具 5、 宠物 6、 婴儿用品 …

利用Tushare获取A股所有股票代码

Tusahre注册链接 https://tushare.pro/register?reg365850 import os import tushare as ts import pandas import datetimetoken 自己的 #可以登录文章首的链接注册获取 pro ts.pro_api(token) dateToday datetime.datetime.today().strftime(%Y%m%d)def GetList():try:d…

chatgpt赋能python:Python语言中的语句输入方法

Python语言中的语句输入方法 作为一门广泛应用于科学计算和计算机编程领域的编程语言&#xff0c;Python以其易读易写、简洁明了的语法特点&#xff0c;广受程序员和科学家的喜爱。本文将重点介绍Python中的语句输入方法&#xff0c;包括基本输入方法、文件读取、网络输入和交…

10款爆火且实用的AIGC工具大盘点

大家好。我是不知名设计师 l1m0_&#xff0c;今天分享内容为&#xff1a;10款爆火且实用的AIGC工具。文中我会跟大家针对10款不同功能优势的AI工具向各位朋友进行介绍&#xff0c;对AI创作感兴趣的朋友一定不能错过&#xff0c;一起来看看吧。 人工智能&#xff08;AI&#xff…

欧洲希望WhatsApp和苹果的iMessage能够开放并共同努力

欧洲将很快迫使苹果、Facebook的Meta和谷歌等消息"守门人"&#xff0c;以确保在用户需要时&#xff0c;消息可以与小公司合作。 欧盟一夜之间通过其新的《数字市场法》&#xff08;DMA&#xff09;使自己成为世界上最严格的美国科技公司监管机构&#xff0c;欧洲政界…

android message to iphone,这款应用可以将苹果的iMessage带到安卓系统

多年来&#xff0c;我们看到一些开发人员尝试使用各种各样的变通方法给Android设备带来iMessage。今天&#xff0c;另一个尝试将iMessage带到Android的方法已经出现。 weMessage是一款新的Android应用程序&#xff0c;它声称通过使用Mac作为iPhone和Android手机之间的中介&…

苹果的Apple GPT要来了?

据外媒消息&#xff0c;苹果正在内部开发类 ChatGPT 的产品&#xff0c;与微软、OpenAI、谷歌、Meta 等科技巨头在生成式 AI 赛道展开竞争。该消息使得苹果股价上涨了 2%。据苹果工程师透露&#xff0c;苹果在内部构建了代号为“Ajax”的大语言模型开发框架&#xff0c;并构建了…

InstructGPT方法简读

InstructGPT方法简读 引言 仅仅通过增大模型规模和数据规模来训练更大的模型并不能使得大模型更好地理解用户意图。由于数据的噪声极大&#xff0c;并且现在的大多数大型语言模型均为基于深度学习的“黑箱模型”&#xff0c;几乎不具有可解释性和可控性&#xff0c;因此&…

歌评-《Rex Incognito 尘世闲游》-陈致逸

时隔一周时间了&#xff0c;终于又找到了时间来更新我的歌评内容。 虽然身被学校关了起来&#xff0c;但是心里还是在歌曲的梦幻世界中畅游hhh。 今天我们来听的歌曲也是 The Stellar Moments 闪耀的群星OST专辑中的一首&#xff0c;代表了璃月城岩王帝君钟离的一首歌曲《尘世闲…

chatgpt赋能python:Python拍照——提高摄影效果的利器

Python拍照——提高摄影效果的利器 在现代社会中&#xff0c;摄影这门艺术已经成为了大众喜爱的一种娱乐和创造的活动。随着技术的不断进步&#xff0c;拍照的方式也不断地发生着变化。而Python编程语言正是一种帮助我们提高摄影效果的利器。下面就让我们来看看&#xff0c;Py…

GPT-4突然降智,爆料OpenAI重新设计构架,用MOE降本增效,官方辟谣网友却不买账...

编辑&#xff1a;润 Lumnia 【导读】最近众多网友反应GPT-4不好用了&#xff0c;后悔充值了。后来网友爆出OpenAI采用MOE重新设计了构架&#xff0c;导致性能收到影响&#xff0c;但是官方一直没有明确答复。 最近一段时间&#xff0c;很多OpenAI的用户反应&#xff0c;GPT-4变…

chatgpt赋能python:Python怎么装Matplotlib

Python怎么装Matplotlib Matplotlib是针对Python语言的绘图库&#xff0c;用于绘制二维图形和三维图形。这个库提供了多种不同的绘图选项&#xff0c;允许用户自由绘制不同类型的图表。Matplotlib是Python科学计算生态系统中最常用的绘图工具之一。 为什么要使用Matplotlib&a…

chatgpt赋能Python-python模块查看

介绍 Python 是一门非常流行且受欢迎的编程语言&#xff0c;它有许多优秀的特性和功能&#xff0c;使其得到了众多开发人员和企业的认可。其中&#xff0c;Python 的模块是一个非常重要的概念&#xff0c;它们允许我们组织和扩展我们的代码库&#xff0c;并在多个项目中重复使…

chatgpt赋能python:Python为坐标轴命名——让图表更加清晰易懂

Python 为坐标轴命名——让图表更加清晰易懂 在数据可视化中&#xff0c;为坐标轴命名是非常重要的。这不仅可以帮助您向读者传达信息&#xff0c;还可以让图表更加清晰易懂。Python 已成为数据科学领域最受欢迎的编程语言之一&#xff0c;并且其绘图库提供了灵活的选项来为坐…

软件开发计划书

1.引言 1.1背景 汽车作为交通工具&#xff0c;在人们的日常行为生活中发挥着极为重要的作用。近十年来&#xff0c;汽车也越来越普遍&#xff0c;不再是一种奢侈品。而很多人也都把汽车当做了一个小家。而当前汽车室内的管理还不够智能化&#xff0c;人们在使用汽车的时候也会…