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
}

代码未优化  需改进

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

  1. Excel中两列数据对比,找出不同数据如何查找重复项并统计重复次数

    Excel中两列数据对比,找出不同数据 问题1 excel如何查找重复项并统计重复次数 问题2

  2. python查找两个数组中相同的元素_找出两个数组的相同元素,最优算法?

    在做新旧接口交替过程中,遇到了老接口和新接口json数据有些不一致的情况,需要比较两个json对象,把相同的元素赋其中一个json对象中变量的值.而且其中一个json最后输出格式还需要改变下属性名,思 ...

  3. java基础—找出两个字符串中最大的子串

    // 找一个字符串的最大子串public static void main(String[] args) {String s1 = "qwerabcdtyuiop";String ...

  4. 快速找出一个数组中的两个数字,让这两个数字之和等于一个给定的值

    我觉得写得很清晰,希望没有侵犯作者的著作权,原文地址http://blog.csdn.net/hackbuteer1/article/details/6699642 快速找出一个数组中的两个数字,让这 ...

  5. 快速找出两个字符串中所有相同的字符

    面试时看到一个试题, 编写算法, 快速找出两个字符串中所有相同的字符. 现实现如下: 1. 利用TreeSet来查找是否有相同的字符(之前是利用TreeSet来查找) 2. 利用HashSet来查找是 ...

  6. JS案例——找出两个数组中的不同元素或对象、数组去重

    一.找出两个数组中的不同元素或对象 1. 数据 var arr1 = ["张瑞淑", "徐海涛", "谢岗岗", "薛鹏" ...

  7. LeetCode简单题之找出两数组的不同

    题目 给你两个下标从 0 开始的整数数组 nums1 和 nums2 ,请你返回一个长度为 2 的列表 answer ,其中: answer[0] 是 nums1 中所有 不 存在于 nums2 中的 ...

  8. 找出两个字符串中最大子字符串,如abractyeyt,dgdsaeactyey的最大子串为actyet

    // 最大子字符串.cpp : 定义控制台应用程序的入口点. // //找出两个字符串中最大子字符串,如"abractyeyt","dgdsaeactyey"的 ...

  9. 找出两个字符串中最长的相同子字符串

    //找出两个字符串中最长的相同子字符串public class Stringdemo {public static void main(String[] args) {String str1 = ne ...

最新文章

  1. 怎么把PDF格式改成EXCEL
  2. 深入理解C++中的mutable关键字 ​
  3. Html5 学习系列(一)认识HTML5
  4. ole db 访问接口 sqlncli 无法启动分布式事务_阿里终面:分布式事务原理
  5. [YTU]_2922(Shape系列-8)
  6. esp32 rtc 时钟设置不对_「STM32」实时时钟(RTC)实验
  7. 虚拟机安装windows ghost版本系统记录完整过程
  8. error LNK2001:unresolved external symbol __imp__@ 解决方法
  9. ae画面颜色一键选取替换修改插件Composite Brush for Mac 1.5.2
  10. android:一个容易被遗忘的强大工具
  11. 多媒体计算机图形,计算机图形学几何造型多媒体可视化虚拟现实.DOC
  12. 如何在短时间内快速提升网站响应速度
  13. [保姆级教程] 从原理到应用,超级详细的MPU6050传感器整理,看完这一篇就够了
  14. 数据库中的E—R图画法
  15. 3w服务器把信息组织成,HTML小白入坑日记~qwq
  16. 三菱Q系列plc11轴运动控制程序
  17. php session fixation,session fixation攻击
  18. EE308_lab1-2
  19. HCIA的OSI基础模型理解
  20. python适合小白学吗_有没有适合零基础小白学习的python课程?

热门文章

  1. 山西省所有计算机中专学校,山西省中专学校大全
  2. 关于IPv6自动配置地址 RA里的A、M、O标记位(纯理论无实验)
  3. LSM 算法的原理(通俗,详细)
  4. 车载无线WIFI让开车不再枯燥
  5. python中for ch in_Python字符串的遍历方式,python
  6. 【CIFS】文件共享服务器
  7. c语言如何调用void函数返回值,C void函数,返回值
  8. HTTP之手机抓包工具篇
  9. Chapter 5 Blood Type——8
  10. memset的用法详解