#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# @Author: tcy
# @Date:   2020-5-3 12:10:53
# @Version:V1.01
# @Last Modified by:   tcy   shanghai songjiang xiaokunshan
# @Last Modified time: 2020-5-7 16:00:00

import cv2,numpy as np

class Array:
    def __init__(self):pass
    def __del__(self):pass

    def add(self,src1,src2,dst=None,mask=None,dtype=None):
        if dtype:
            return cv2.add(src1,src2,dst,mask,dtype)
        else:
            return cv2.add(src1,src2,dst,mask)

    def addWeighted(self,src1,alpha,src2,beta,gamma=0,dst=None,dtype=None):
        if dtype:
            return cv2.addWeighted(src1,alpha,src2,beta,gamma,dst,dtype)
        else:
            return cv2.addWeighted(src1,alpha,src2,beta,gamma,dst)

    def sub(self,src1,src2,dst=None,mask=None,dtype=None):
        if dtype:
            return cv2.subtract(src1,src2,dst,mask,dtype)
        else:
            return cv2.subtract(src1,src2,dst,mask)

    def mul(self,src1,src2,dst=None,scale=None,dtype=None):
        """
            multiply(src1, src2[, dst[, scale[, dtype]]]) -> dst
        .   @brief Calculates the per-element scaled product of two arrays.
        .
        .   The function multiply calculates the per-element product of two arrays:
        .   There is also a @ref MatrixExpressions -friendly variant of the first function. See Mat::mul .
        .   For a not-per-element matrix product, see gemm .
        .
        .   @note Saturation is not applied when the output array has the depth
        .   CV_32S. You may even get result of an incorrect sign in the case of  overflow.
        .   @param src1 first input array.
        .   @param src2 second input array of the same size and the same type as src1.
        .   @param dst output array of the same size and type as src1.
        .   @param scale optional scale factor.
        .   @param dtype optional depth of the output array
        .   @sa add, subtract, divide, scaleAdd, addWeighted, accumulate, accumulateProduct, accumulateSquare,
        .   Mat::convertTo

        """
        if dtype:
            if scale:
                return cv2.multiply(src1,src2,dst,scale,dtype)
            else:
                return cv2.multiply(src1,src2,dst,dtype=dtype)
        else:
            if scale:
                return cv2.multiply(src1,src2,dst,scale)
            else:
                return cv2.multiply(src1,src2,dst)

    def div(self,src1,src2,dst=None,scale=None,dtype=None):
        """
        divide(src1, src2[, dst[, scale[, dtype]]]) -> dst
        .   @brief Performs per-element division of two arrays or a scalar by an array.
        .
        .   The function cv::divide divides one array by another:
        .   \f[\texttt{dst(I) = saturate(src1(I)*scale/src2(I))}\f]
        .   or a scalar by an array when there is no src1 :
        .   \f[\texttt{dst(I) = saturate(scale/src2(I))}\f]
        .
        .   Different channels of multi-channel arrays are processed independently.
        .   For integer types when src2(I) is zero, dst(I) will also be zero.
        .
        .   @note In case of floating point data there is no special defined behavior for zero src2(I) values.
        .   Regular floating-point division is used.
        .   Expect correct IEEE-754 behaviour for floating-point data (with NaN, Inf result values).
        .
        .   @note Saturation is not applied when the output array has the depth CV_32S. You may even get
        .   result of an incorrect sign in the case of overflow.
        .   @param src1 first input array.
        .   @param src2 second input array of the same size and type as src1.
        .   @param scale scalar factor.
        .   @param dst output array of the same size and type as src2.
        .   @param dtype optional depth of the output array; if -1, dst will have depth src2.depth(), but in
        .   case of an array-by-array division, you can only pass -1 when src1.depth()==src2.depth().
        .   @sa  multiply, add, subtract

        """
        if dtype:
            if scale:
                return cv2.divide(src1,src2,dst,scale,dtype)
            else:
                return cv2.divide(src1,src2,dst,dtype=dtype)
        else:
            if scale:
                return cv2.divide(src1,src2,dst,scale)
            else:
                return cv2.divide(src1,src2,dst)

    def bit_and(self,src1,src2,dst=None,mask=None):
        return cv2.bitwise_and(src1,src2,dst,mask)

    def bit_or(self,src1,src2,dst=None,mask=None):
        return cv2.bitwise_or(src1,src2,dst,mask)

    def bit_not(self,src,dst=None,mask=None):
        return cv2.bitwise_not(src,dst,mask)

    def bit_xor(self,src1,src2,dst=None,mask=None):
        return cv2.bitwise_xor(src1,src2,dst,mask)

    def pow(self,src,power,dst=None):# 乘方
        return cv2.pow(src,power,dst)

    def sqrt(self,src,dst=None):           # 开方
        return cv2.sqrt(src,dst)

    def max(self,src1,src2,dst=None):# 最大值
        return cv2.max(src1,src2,dst)

    def min(self,src1,src2,dst=None):# 最大值
        return cv2.min(src1,src2,dst)

    def meanstd(self,image,mean=None,stddev=None,mask=None):
        image=cv2.imread(image,0) if isinstance(image,str) else image
        channels=len(image.shape)
        if channels==3:
            image=cv2.cvtColor(image,cv2.COLOR_BGR2GRAY)

        result=cv2.meanStdDev(image,mean,stddev,mask)
        return result[0][0][0],result[1][0][0]

    def test_add(self,gray1,gray2):
        gray1=cv2.imread(gray1) if isinstance(gray1,str) else gray1
        gray2=cv2.imread(gray2) if isinstance(gray2,str) else gray2

        result = self.add(gray1,gray2)
        result = self.sub(gray1,gray2)
        result=self.mul(gray1,gray2,None)
        result=self.div(gray1,gray2,None)

        result = self.bit_and(gray1,gray2)
        result = self.bit_or(gray1,gray2)
        result = self.bit_not(gray1)
        result = self.bit_xor(gray1,gray2)

        result = self.max(gray1,gray2)
        result = self.min(gray1,gray2)

        print('dtype.name=',gray1.dtype.name)
        print('meanstd=',self.meanstd(gray1))#(43.09787760416667, 60.29981335200884)

        cv2.imshow("result",result)
        cv2.waitKey(0)

    def getChannels(self,image):
        return len(image.shape)

    def getCenterPoint(self,image):
        h,w=image.shape[0:2]
        cx,cy=int(w*0.5),int(h*0.5)
        return cx,cy

    def getRectPt1Pt2(self,center:'cx,xy',w:int,h:int):
        cx,cy=center
        pt1=(int(cx-0.5*w),int(cy-0.5*h))
        pt2=(int(cx+0.5*w),int(cy+0.5*h))

        return pt1,pt2

    def bitplane(self,image, channel:'int'=0, n_RD:'int'=7, value=255)->np.ndarray:  # 灰度图:位平面提取
        """
        灰度图:位平面提取
        """
        img = image if type(image) == type(np.ndarray(())) else cv2.imread(image)
        img = img[:, :, channel] if len(img.shape) == 3 else img

        r, c = img.shape
        x = np.zeros((r, c, 8), dtype=np.uint8)

        for i in range(8):             # a7权重最高
            x[:, :, i] = 2 ** i

        r = np.zeros((r, c, 8), dtype=np.uint8)
        r[:, :, n_RD] = cv2.bitwise_and(img, x[:, :, n_RD])

        mask = r[:, :, n_RD] > 0  # 阈值处理
        r[mask] = value

        return r[:, :, n_RD]

    def bitplane1(self,image, channel:'int'=0, n_RD:'int'=7, value=255)->np.ndarray:  # 灰度图:位平面提取
        """
        灰度图:位平面提取
        将像素右移动n位,对2取模
        """
        img = image if type(image) == type(np.ndarray(())) else cv2.imread(image)
        img = img[:, :, channel] if len(img.shape) == 3 else img

        img = np.right_shift(img, n_RD)
        img = np.mod(img, 2)

        mask = img[:, :] > 0  # 阈值处理
        img[mask] = value

        return img

    def inRange(self, src: 'np.ndarray', lowerb, upperb) -> np.ndarray:#可处理彩色图
        """
        inRange(src, lowerb, upperb[, dst]) -> dst

        作用: 【gray二值化,生成mask;colorimage看不出什么用途?】
        实现多通道二值化功能;实现对目前区域的提取与分割
        在两个阈值内的像素值设置为白色255,而不在阈值区间内的像素值设置为黑色0,该功能类似于之间所讲的双阈值化操作。

        :param src: ndarray 原图
        :param lowerb:   下边界的数组或标量--图像中低于这个lower_red的值,图像值变为0
        :param upperb:  上边界数组或标量--图像中高于这个upper_red的值,图像值变为0
        :return: ndarray  输出图像--value 在[lowerb,upperb]范围内时=255,不在=0
                                    与输入图像src 尺寸相同且为CV_8U 类型。

        处理方式:
        单通道:cv2.inRange(gray,127,200)生成了一幅二值化的输出图像
        多通道:
                        lower =  np.array([20, 20, 20],dtype=np.uint8)#不能为标量
                        higher= np.array([200, 200, 200],dtype=np.uint8)
                        result=cv2.inRange(arr2,lower,higher)

        """
        return cv2.inRange(src,lowerb,upperb)

    def copy(self,mat,order='C'):#图像复制:彩色 0.0562 ms
        """
        :param mat: ndarray
        :param order: str "C"
        :return: ndarray
        """
        return mat.copy(order)

    def copyTo(self,src,mask:'(row1,row2,cols1,col2)'=None):
        """
        :param src: source image  color or gray.
        :param mask: int,int,int,int  choose the ROI range.
        :return: get the ROI range image.outside ROI is 0.

        cv2.copyTo(src,mask)
        用途:将小图像拷贝到大图像中
        :param src: 原图与模板进行运算后得到的结果拷贝给dst
        :param mask: 必须为CV_8U,可以是单通道也可以是多通道
        :return: ndarray
        说明:
        拷贝后仅仅有ROI区域的图形,且图形不在中心
        深拷贝,复制了矩阵头和矩阵数据
        mask=np.zeros(img2_copy.shape,dtype=img2_copy.dtype)
        mask[x_1:x_2,y_1:y_2]=255
        img3=cv2.copyTo(img2_copy,mask)

        """
        img1=cv2.imread(src) if isinstance(src,str) else src
      
        if mask==None:return img1.copy()
        r1,r2,c1,c2=mask
        mask=np.zeros(img1.shape,dtype=img1.dtype)
        mask[r1:r2,c1:c2]=255

        return cv2.copyTo(src,mask)

    def __get_mask_image_same_centerPoint(self,mask,image):
        r1,r2,c1,c2=mask
        dr_mask,dc_mask=abs(r2-r1),abs(c2-c1)

        cx,cy=self.getCenterPoint(image)
        r1,r2=int(cy-dr_mask*0.5),int(cy+dr_mask*0.5)
        c1,c2=int(cx-dc_mask*0.5),int(cx+dc_mask*0.5)

        return r1,r2,c1,c2

    def copyROI(self,src,src2,mask:'(row1,row2,cols1,col2)',pt1:'(int,int)'=None,center=True):
        """
        :param src: 要拷贝选择区域的图像
        :param src2: 背景图像
        :param mask: src图像中选择的ROI
        :param pt1: 将ROI图像放置在结果图指定的左上角(行,列)忽略center
        :param center: 当pt1=None时若为True  ROI放置在中心,佛则原来位置
        :return:ndarray
        """
        img1=cv2.imread(src) if isinstance(src,str) else src
        img2=cv2.imread(src2) if isinstance(src2,str) else src2

        r1,r2,c1,c2=mask
        roi=img1[r1:r2,c1:c2]

        if pt1:
            r1,r2,c1,c2=(pt1[0],pt1[0]+abs(r2-r1),pt1[1],pt1[1]+abs(c2-c1))
        else:
            r1,r2,c1,c2=self.__get_mask_image_same_centerPoint(mask,img2)  if center else mask

        img2[r1:r2,c1:c2]=roi

        return img2

    def imageCenterPointRect(self,img,rect:'pt1,pt2',center:'cx,xy'=None,xoffset:int=None,yoffset:int=None):
        """
        :param ceter: 将矩形定位在图像指定的中心点或指定相对图像左上角0,0的偏移量
        :param w: mask矩形宽带
        :param h: mask矩形高度
        :return: 矩形右上左下角中心点坐标pt1,pt2,pt
        """
        if len(rect)==2:
            pt1,pt2=rect
            w_rect,h_rect=abs(pt2[0]-pt1[0]),abs(pt2[1]-pt1[1])
        elif len(rect)==4:
            x1,y1,x2,y2=rect
            w_rect,h_rect=abs(x2-x1),abs(y2-y1)
        else:
            raise Exception("Parameter rect error!")

        if center:
            cx,cy=center
        elif bool(xoffset) and bool(yoffset):
            cx,cy=int(xoffset+0.5*w_rect),(yoffset+0.5*h_rect)

        else:
            if not isinstance(img,np.ndarray):
                raise Exception("Parameter img error!")
            cx,cy=int(img.shape[1]/2),int(img.shape[0]/2)

        pt=(cx,cy)
        pt1=(int(cx-0.5*w_rect),int(cy-0.5*h_rect))
        pt2=(int(cx+0.5*w_rect),int(cy+0.5*h_rect))

        h,w=img.shape[0:2]
        b1=pt[0]>w or pt[1]>h
        b2=pt1[0]>w or pt1[1]>h
        b3=pt2[0]>w or pt2[1]>h

        if b1 or b2 or b3:
            raise Exception("Th_recte rect out th_recte range !")

        return pt1,pt2,pt

    def test_copy(self,img1,img2):
        img1=cv2.imread(img1) if isinstance(img1,str) else img1
        img2=cv2.imread(img2) if isinstance(img2,str) else img2
        channels1,channels2=len(img1.shape),len(img2.shape)
        if channels1==3:
            img11=cv2.cvtColor(img1,cv2.COLOR_BGR2GRAY)
        if channels2==3:
            img12=cv2.cvtColor(img2,cv2.COLOR_BGR2GRAY)

        print('img1.shape=',img1.shape,img2.shape,img11.shape,img12.shape)
        # (480, 640, 3) (480, 640, 3) (480, 640) (480, 640)

        #test copy
        tmp1=self.copy(img1)
        tmp2=self.copy(img11)
        cv2.imshow('s1',img1)
        cv2.imshow('s2',tmp1)
        cv2.imshow('s3',img11)
        cv2.imshow('s4',tmp2)
        print('tmp1.shape=',tmp1.shape,tmp2.shape)#(480, 640, 3) (480, 640)

        #test copyTo
        tmp3=self.copyTo(img1,(200,400,0,500))
        tmp4=self.copyTo(img11,(200,400,0,500))
        cv2.imshow('s1',img1)
        cv2.imshow('s2',tmp3)
        cv2.imshow('s3',img11)
        cv2.imshow('s4',tmp4)
        print('tmp3.shape=',tmp3.shape,tmp4.shape)#(480, 640, 3) (480, 640)

        #test copyROI()
        tmp5=self.copyROI(img1,img2,(200,400,0,500),center=False)
        tmp6=self.copyROI(img11,img12,(200,400,0,500),center=False)
        cv2.imshow('s1',img1)
        cv2.imshow('s2',tmp5)
        cv2.imshow('s3',img11)
        cv2.imshow('s4',tmp6)

        print('tmp5.shape=',tmp3.shape,tmp4.shape)#(480, 640, 3) (480, 640)

        tmp7=self.copyROI(img1,img2,(200,400,0,500))
        tmp8=self.copyROI(img11,img12,(200,400,0,500))
        cv2.imshow('s1',img1)
        cv2.imshow('s2',tmp7)
        cv2.imshow('s3',img11)
        cv2.imshow('s4',tmp8)

        tmp7=self.copyROI(img1,img2,(200,400,0,500),(100,0))
        tmp8=self.copyROI(img11,img12,(200,400,0,500),(100,0))
        cv2.imshow('s1',img1)
        cv2.imshow('s2',tmp7)
        cv2.imshow('s3',img11)
        cv2.imshow('s4',tmp8)

        cv2.waitKey()

    def test_inRange(self):
        from Image.data import Data
        arr1=Data.Data.arr2D
        arr2=Data.Data.arr3D
        print(arr1)
        print('==============')
        print(a.inRange(arr1,23,33))
        """
        [[11 12 13 14]
         [21 22 23 24]
         [31 32 33 34]]
        ==============
        [[  0   0   0   0]
         [  0   0 255 255]
         [255 255 255   0]]
        """

    def ROI(self,img,pt1,pt2):
        """
        :param img: np.ndarray or str
        :param pt1: rect top left corner
        :param pt2:rect right down corner
        :return:ndarray
        """
        img=cv2.imread(img,1) if isinstance(img,str) else img
        mask = np.zeros(img.shape[:2], dtype="uint8")
        mask[pt1[0]:pt2[0],pt1[1]:pt2[1]]=255

        return cv2.bitwise_and(img, img,mask)

    def ROI_1(self,img,pt1,pt2):
        """
        :param img: np.ndarray or str
        :param pt1: rect top left corner
        :param pt2:rect right down corner
        :return:ndarray
        """
        img=cv2.imread(img,1) if isinstance(img,str) else img
        mask = np.zeros(img.shape[:2], dtype="uint8")
        cv2.rectangle(mask,pt1,pt2,255,-1)

        return cv2.bitwise_and(img, img, mask=mask)

    def ROI_2(self,img,row1,row2,col1,col2):
        """
        返回选择区域的图像彩色或灰度 rows=row2-row1,cols=col2-col1
        """
        img=cv2.imread(img,1) if isinstance(img,str) else img
        return img[row1:row2,col1:col2]

    def test_ROI(self,image):
        pt1,pt2=(500,250),(300,5)
        img=self.ROI(image,pt1,pt2)
        img1=self.ROI1(image,pt1,pt2)
        cv2.imshow('s1',img)
        cv2.imshow('s2',img1)
        cv2.waitKey()

#===========================================================================================
if __name__=="__main__":
    import os

    girl=os.getcwd()+'\\data\\girl.jpg'
    flower=os.getcwd()+'\\data\\flower.jpg'
    gray1=os.getcwd()+'\\data\\fastener1.jpg'
    gray2=os.getcwd()+'\\data\\fastener2.jpg'

    a=Array()

    a.test_add(gray1,gray2)
    a.test_ROI(girl)
    a.test_ROI(gray1)

    a.test_inRange()
    a.test_copy(girl,flower)

    








 

Logo

技术共进,成长同行——讯飞AI开发者社区

更多推荐