GoCV下实现多图片单窗口内同时显示

问题

OPENCV的IMShow一次只能显示一张图片,但是很多时候我们需要同时显示多张图片。

方案一

网上搜索解决方案,多数是基于Python的,要么用numpy的hstack/vstack,要么使用plt解决。所幸,在opencv函数中找到了hconcat和vconcat,但是hconcat需要图片高度一致,vconcat需要图片宽度一致。我这里选用hconcat,以第一张图片的高度为基准,其他图片resize到同样高度,但是为了图片不变形,宽度要按照高度变化比例缩放。

 func ShowImages(title string,imgs ...cv.Mat,)*cv.Window{
   if len(imgs)==0{
     fmt.Println("[showImg] should give me at least one image!")
     return nil
   }
   img, width, height:=StackImagesHV(imgs...)  
   defer func(img cv.Mat){   
     if img.Size()[0]!=imgs[0].Size()[0]{ img.Close()  }
   }(img)
   win:=cv.NewWindow(title)
   win.SetWindowTitle(title)
   win.ResizeWindow(width, height )
   //
   win.IMShow(img)
   return win
 }
 func StackImagesH(imgs ...cv.Mat) (img cv.Mat, width int, height int){
   if len(imgs)==0{
     panic("[StackImagesH] should give me at least one image!")
   }
   img=cv.NewMat() 
   if len(imgs)==1{    
     img = imgs[0].Clone()
     width,height=ImageSize(img)
     return
   }
   
   imgs[0].CopyTo(&img)    
   width,height = ImageSize(imgs[0])
 for i:=1;i<len(imgs);i++{
     pic:=imgs[i]    
     tw,th:=ImageSize(pic)   
     if th!=height {
       np,nw:=ResizeImageByHeight(pic, height)     
       width += nw
       cv.Hconcat(img,  np ,&img)
       np.Close()
       
     }else{ 
       cv.Hconcat(img,  pic ,&img)
       width += tw
     }
   }
 return img,width,height
 }

 

方案二

方案一的解决方案有明显的局限性,由于只能单纯的横向或者纵向拼接,当图片比较多的时候,明显不太美观实用。经过一段时间思考想到了自己手动拼接图片,按照先行后列的方式,生成一个大图片,而且自己还可以定义行列的间隔(当然,方案一中也是可以通过生成空白图片的方式添加图片间隔的),不废话上代码。

 func StackImagesHV(imgs ...cv.Mat) (bigImg cv.Mat, colWidth int, rowHeight int){  
   interval:= 4 // 图片间的间隔
   imgCount:=len(imgs)
   if imgCount<=4 { return StackImagesH(imgs...)}
   colCount:=4
   if imgCount<7{
     colCount= imgCount/2 + imgCount%2
   }else if imgCount%3==0{
     colCount = imgCount/3
   }
   rowCount:= imgCount / colCount 
   if imgCount % colCount>0{
     rowCount +=1
   } 
   firstImg:=imgs[0]
   _,rowHeight=ImageSize(firstImg) 
   newImgs:=make([]cv.Mat,len(imgs))
   defer func(){
     for _,np:=range newImgs{
       np.Close()
     } 
   }()
   totalHeight:=rowCount*rowHeight + interval*(rowCount-1)
   colWidth=0   // set to max width images' width
   for row:=0;row<rowCount;row++{    
     for col:=0;col<colCount;col++{
       i:=row*colCount+ col
       if i>=imgCount{ break; }
       np,w:=ResizeImageByHeight(imgs[i],rowHeight)
       newImgs[i]=np     
       if w>colWidth{
         colWidth = w
       }
     }
   }
   totalWidth:=colWidth* colCount  + interval*(colCount-1)
   //
   fillColor:= cv.Scalar{Val1:255,Val2:0,Val3:0,Val4:0xff} // blue, for opencv default BGR color space
   bigImg= cv.NewMatWithSizeFromScalar(fillColor, totalHeight,totalWidth,firstImg.Type())
   // loop region copy
   for row:=0;row<rowCount;row++{
     left:=0
     top:=row*rowHeight + row*interval
     for col:=0; col<colCount; col++{
       i:=row*colCount+ col
       if i>=imgCount{ break; }
       np:=newImgs[i]
       picW,_:=ImageSize(np)                 
       rt:=image.Rect(left, top, left+picW, top+rowHeight )
       left += colWidth + interval
       tmpImg:= bigImg.Region(rt)
       np.CopyTo(&tmpImg)
   }
   return bigImg, totalWidth, totalHeight
 }
 

效果图

 

发布于 2023-06-26 14:14・IP 属地天津
posted @ 2023-06-27 09:41  柒零壹  阅读(25)  评论(0编辑  收藏  举报