How do I locate the center of a piece of paper in a photo?

Hello,
I have adjusted my code and am no longer getting any errors. When I am creating a histogram to find the center point of a white paper I am getting it a bit off-center.

Can anyone help?

Here is an image:

I would like the yellow dot in the center of the paper.

A tutorial I have been using: Finding Lane Curve | Self Driving Car with Lane Detection using Raspberry Pi p.4 - YouTube
My Code:


import cv2
import numpy as np
import Thresh
import ROI

def empty(x):
    pass

def getHistogram(img,minPer=0.1,display=True):
    
    histValues = np.sum(img,axis=0)
    maxValue = np.max(histValues)
    minValue = minPer*maxValue

    indexArray = np.where(histValues>= minValue)
    basePoint = int(np.average(indexArray))
    w = img.shape[1]
    h = img.shape[0]
    print(type(w))

    if display:
        imgHist = np.zeros((img.shape[0],img.shape[1],3),np.uint8)
        for x,intensity in enumerate(histValues):
            temp=0
            for i in intensity:
                temp+= int(i)
            cv2.line(imgHist,(int(x),int(w)),(int(x),int(h)-temp//255),(255,0,255),1)
            cv2.circle(imgHist,(basePoint,int(h)),20,(0,255,255),cv2.FILLED)
        return basePoint,imgHist

    return basePoint


    print(basePoint)
curveList = []
avgVal=10

def getCurve(frame):

   
    # Step 1: Threhold Paper
    frame,mask,result = Thresh.thresh(frame)

    frameWPoints = frame.copy()
    warpThresh = mask.copy()
    warpFrame = frame.copy()

    # Step 2: Define ROI
    hT, wT, c = frame.shape
    points = ROI.valTrackbars()
    # Step 3: Warp Image
    warpFrame = ROI.warpImg(warpFrame,points,wT,hT)
    warpThresh = ROI.warpImg(warpThresh,points,wT,hT)
    imgWarpPoints = ROI.drawPoints(frameWPoints,points)
    # Step 4: Apply Histogram - Summation of Pixels
    basePoint,imgHist = getHistogram(warpThresh)
    # Step 5: Calculate Curve
   # print(curveRaw)
    # Step 6: Filter Curve
    
    # Step 7: Display
    #print(curve)
    complete = frame
    curve = 0
    return int(curve),frame,mask,warpFrame,warpThresh,imgWarpPoints,imgHist,complete





if __name__ == "__main__":
    

    cv2.namedWindow("HSV")
    cv2.resizeWindow("HSV", 640, 240)
    cv2.createTrackbar("HUE Min", "HSV", 0, 255, empty)
    cv2.createTrackbar("HUE Max", "HSV", 179, 255, empty)
    cv2.createTrackbar("SAT Min", "HSV", 0, 255, empty)
    cv2.createTrackbar("SAT Max", "HSV", 255, 255, empty)
    cv2.createTrackbar("VALUE Min", "HSV", 113, 255, empty)
    cv2.createTrackbar("VALUE Max", "HSV", 255, 255, empty)
    
    intialTrackBarVals = [50, 108, 0, 140]
    ROI.initializeTrackbars(intialTrackBarVals)
    
    vid = cv2.VideoCapture(0)
    while(1):
        _,frame = vid.read()
        frame = cv2.resize(frame,(480,240))
        curve,frame,mask,warp,warpThresh,roi,histogram,complete = getCurve(frame)
        
        l1 =np.concatenate((frame,mask),axis=1)
        l2 =np.concatenate((roi,warp,warpThresh),axis=1)
        l3 =np.concatenate((histogram,complete),axis=1)
        cv2.imshow("THRESH",l1)
        cv2.imshow("TRANSFORM",l2)
        cv2.imshow("RESULT",l3)

        if cv2.waitKey(1) & 0xFF == ord('q'):
            break
    

    vid.release()

    cv2.destroyAllWindows()

Thanks in advance,
Dev_101

i’d rather ditch the whole ROI / histogram approach, and try to find the center from the binary image using cv2.moments()
https://docs.opencv.org/4.x/d0/d49/tutorial_moments.html

(please be aware that noone here can reproduce your code due to missing ROI / Thresh modules)

Ok, I understand. I prefer the histogram approach because it is my first time using the OpenCV framework.

Here are all my modules:

thresh.py:

import cv2
import numpy as np

def empty(x):
    pass

def thresh(frame):
    
    frame = cv2.resize(frame, (480,240))

    imgHsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV)

    h_min = cv2.getTrackbarPos("HUE Min", "HSV")
    h_max = cv2.getTrackbarPos("HUE Max", "HSV")
    s_min = cv2.getTrackbarPos("SAT Min", "HSV")
    s_max = cv2.getTrackbarPos("SAT Max", "HSV")
    v_min = cv2.getTrackbarPos("VALUE Min", "HSV")
    v_max = cv2.getTrackbarPos("VALUE Max", "HSV")
    
    lower = np.array([h_min, s_min, v_min])
    upper = np.array([h_max, s_max, v_max])
    mask = cv2.inRange(imgHsv, lower, upper)
    result = cv2.bitwise_and(frame, frame, mask=mask)
 
    mask = cv2.cvtColor(mask, cv2.COLOR_GRAY2BGR)
    
    return frame,mask,result

ROI.py

import cv2
import numpy as np

def nothing(x):
    pass

def warpImg (img,points,w,h,inv=False):
    pts1 = np.float32(points)
    pts2 = np.float32([[0,0],[w,0],[0,h],[w,h]])
    if inv:
        matrix = cv2.getPerspectiveTransform(pts2,pts1)
    else:
        matrix = cv2.getPerspectiveTransform(pts1,pts2)
    imgWarp = cv2.warpPerspective(img,matrix,(w,h))
    return imgWarp


def initializeTrackbars(intialTracbarVals,wT=480, hT=240):
    cv2.namedWindow("Trackbars")
    cv2.resizeWindow("Trackbars", 360, 240)
    cv2.createTrackbar("Width Top", "Trackbars", intialTracbarVals[0],wT//2, nothing)
    cv2.createTrackbar("Height Top", "Trackbars", intialTracbarVals[1], hT, nothing)
    cv2.createTrackbar("Width Bottom", "Trackbars", intialTracbarVals[2],wT//2, nothing)
    cv2.createTrackbar("Height Bottom", "Trackbars", intialTracbarVals[3], hT, nothing)
    
def valTrackbars(wT=480, hT=240):
    widthTop = cv2.getTrackbarPos("Width Top", "Trackbars")
    heightTop = cv2.getTrackbarPos("Height Top", "Trackbars")
    widthBottom = cv2.getTrackbarPos("Width Bottom", "Trackbars")
    heightBottom = cv2.getTrackbarPos("Height Bottom", "Trackbars")
    points = np.float32([(widthTop, heightTop), (wT-widthTop, heightTop),
                      (widthBottom , heightBottom ), (wT-widthBottom, heightBottom)])
    return points


def drawPoints(img,points):
    for x in range( 0,4):
        cv2.circle(img,(int(points[x][0]),int(points[x][1])),15,(0,0,255),cv2.FILLED)
    return img

curve.py:


import cv2
import numpy as np
import Thresh
import ROI

def empty(x):
    pass

def getHistogram(img,minPer=0.1,display=True):
    
    histValues = np.sum(img,axis=0)
    maxValue = np.max(histValues)
    minValue = minPer*maxValue

    indexArray = np.where(histValues>= minValue)
    basePoint = int(np.average(indexArray))
    w = img.shape[1]
    h = img.shape[0]
    print(type(w))

    if display:
        imgHist = np.zeros((img.shape[0],img.shape[1],3),np.uint8)
        for x,intensity in enumerate(histValues):
            temp=0
            for i in intensity:
                temp+= int(i)
            cv2.line(imgHist,(int(x),int(w)),(int(x),int(h)-temp//255),(255,0,255),1)
            cv2.circle(imgHist,(basePoint,int(h)),20,(0,255,255),cv2.FILLED)
        return basePoint,imgHist

    return basePoint


    print(basePoint)
curveList = []
avgVal=10

def getCurve(frame):

   
    # Step 1: Threhold Paper
    frame,mask,result = Thresh.thresh(frame)

    frameWPoints = frame.copy()
    warpThresh = mask.copy()
    warpFrame = frame.copy()

    # Step 2: Define ROI
    hT, wT, c = frame.shape
    points = ROI.valTrackbars()
    # Step 3: Warp Image
    warpFrame = ROI.warpImg(warpFrame,points,wT,hT)
    warpThresh = ROI.warpImg(warpThresh,points,wT,hT)
    imgWarpPoints = ROI.drawPoints(frameWPoints,points)
    # Step 4: Apply Histogram - Summation of Pixels
    basePoint,imgHist = getHistogram(warpThresh)
    # Step 5: Calculate Curve
   # print(curveRaw)
    # Step 6: Filter Curve
    
    # Step 7: Display
    #print(curve)
    complete = frame
    curve = 0
    return int(curve),frame,mask,warpFrame,warpThresh,imgWarpPoints,imgHist,complete





if __name__ == "__main__":
    

    cv2.namedWindow("HSV")
    cv2.resizeWindow("HSV", 640, 240)
    cv2.createTrackbar("HUE Min", "HSV", 0, 255, empty)
    cv2.createTrackbar("HUE Max", "HSV", 179, 255, empty)
    cv2.createTrackbar("SAT Min", "HSV", 0, 255, empty)
    cv2.createTrackbar("SAT Max", "HSV", 255, 255, empty)
    cv2.createTrackbar("VALUE Min", "HSV", 113, 255, empty)
    cv2.createTrackbar("VALUE Max", "HSV", 255, 255, empty)
    
    intialTrackBarVals = [50, 108, 0, 140]
    ROI.initializeTrackbars(intialTrackBarVals)
    
    vid = cv2.VideoCapture(0)
    while(1):
        _,frame = vid.read()
        frame = cv2.resize(frame,(480,240))
        curve,frame,mask,warp,warpThresh,roi,histogram,complete = getCurve(frame)
        
        l1 =np.concatenate((frame,mask),axis=1)
        l2 =np.concatenate((roi,warp,warpThresh),axis=1)
        l3 =np.concatenate((histogram,complete),axis=1)
        cv2.imshow("THRESH",l1)
        cv2.imshow("TRANSFORM",l2)
        cv2.imshow("RESULT",l3)

        if cv2.waitKey(1) & 0xFF == ord('q'):
            break
    

    vid.release()

    cv2.destroyAllWindows()


Again,
I have tried for hours and don’t understand why it is not working properly, so any help would be appreciated,

Thanks,
Dev101

the histogram part is NOT from opencv

again, please realize, that we cannot help with code we cant reproduce

I understand, but I gave you the missing modules.

take one picture and save it. provide this picture as input for everyone to work on. make sure it is not a screenshot or anything like that, but the original untouched picture.

we can’t use your webcam, hence “not reproducible”.

This is the image:
openCV

that picture is 480x240. is that the resolution you expect to work with?

and you need to find… two corners in that picture, or four corners?

if you need the center, but the center isn’t marked, you need the four corners