text overlay issue? - directshow.net

by using directshow.net i can able to record the video and with recording i am doing text overlay for this i configured sample grabber and in buffercb method i am working on frames here is the code..
int ISampleGrabberCB.BufferCB(double SampleTime, IntPtr pBuffer, int BufferLen)
{
Graphics g;
String s;
float sLeft;
float sTop;
SizeF d;
g = Graphics.FromImage(bitmapOverlay);
g.Clear(System.Drawing.Color.Transparent);
g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
// Prepare to put the specified string on the image
g.DrawRectangle(System.Drawing.Pens.Transparent, 0, 0, 240 - 1, 176 - 1);
g.DrawRectangle(System.Drawing.Pens.Transparent, 1, 1, 240 - 3, 176 - 3);
d = g.MeasureString(m_String + "\n" + DateTime.Now.ToString("G"), fontOverlay);
sLeft = (240 - d.Width) / 2;
sTop = (176 - d.Height) / 2;
g.DrawString(m_String + "\n" + DateTime.Now.ToString("G"), fontOverlay, System.Drawing.Brushes.Black,
sLeft, sTop, System.Drawing.StringFormat.GenericTypographic);
// need to flip the bitmap so it's the same orientation as the
// video buffer
bitmapOverlay.RotateFlip(RotateFlipType.RotateNoneFlipY);
// create and copy the video's buffer image to a bitmap
Bitmap v;
v = new Bitmap(240, 176, 1056,
PixelFormat.Format24bppRgb, pBuffer);
g = Graphics.FromImage(v);
g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
// draw the overlay bitmap over the video's bitmap
g.DrawImage(bitmapOverlay, 0, 0, bitmapOverlay.Width, bitmapOverlay.Height);
// dispose of the various objects
g.Dispose();
v.Dispose();
// Increment frame number. Done this way, frame are zero indexed.
m_Count++;
return 0;
}
my problem is,when i start program it shows me text overlay in preview window but when i open recorded file text overlay is not continues..i think i am missing some frames..on some frames overlay is their but its not continues..its flicking.
can any one help?

ok i got the problem!!
in the above code,BufferCB takes too long time to process the current video frame.its like let frame A is still in middle process before process complete frame B comes in.
so to minimize the processing in BufferCB i have remove the where bitmap image is set
this line of code i put into an function
g = Graphics.FromImage(bitmapOverlay);
g.Clear(System.Drawing.Color.Transparent);
g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
// Prepare to put the specified string on the image
g.DrawRectangle(System.Drawing.Pens.Transparent, 0, 0, 240 - 1, 176 - 1);
g.DrawRectangle(System.Drawing.Pens.Transparent, 1, 1, 240 - 3, 176 - 3);
d = g.MeasureString(m_String + "\n" + DateTime.Now.ToString("G"), fontOverlay);
sLeft = (240 - d.Width) / 2;
sTop = (176 - d.Height) / 2;
g.DrawString(m_String + "\n" + DateTime.Now.ToString("G"), fontOverlay, System.Drawing.Brushes.Black,
sLeft, sTop, System.Drawing.StringFormat.GenericTypographic);
// need to flip the bitmap so it's the same orientation as the
// video buffer
bitmapOverlay.RotateFlip(RotateFlipType.RotateNoneFlipY);
and this function is called before media.run is called.

Related

Window positioning results in space around windows on Windows 10

I have some code that positions windows to screen quadrants. It works fine on Windows XP, 7, and 8/8.1. However, on Windows 10, there is a weird gap between windows. The extra space surrounds the window on all 4 sides. I presume it has something to do with window borders, but can't figure out how to correct the problem. Any input would be highly appreciated. The code is as follows:
// Get monitor info
HMONITOR hm = MonitorFromWindow(hWnd, MONITOR_DEFAULTTONEAREST);
MONITORINFO mi;
mi.cbSize = sizeof(mi);
GetMonitorInfo(hm, &mi);
// Set screen coordinates and dimensions of monitor's work area
DWORD x = mi.rcWork.left;
DWORD y = mi.rcWork.top;
DWORD w = mi.rcWork.right - x;
DWORD h = mi.rcWork.bottom - y;
switch (corner) {
case 0: // Left top
SetWindowPos(hWnd, HWND_TOP, x, y, w / 2, h / 2, SWP_NOZORDER);
break;
case 1: // Right top
SetWindowPos(hWnd, HWND_TOP, x + w / 2, y, w / 2, h / 2, SWP_NOZORDER);
break;
case 2: // Right bottom
SetWindowPos(hWnd, HWND_TOP, x + w / 2, y + h / 2, w / 2, h / 2, SWP_NOZORDER);
break;
case 3: // Left bottom
SetWindowPos(hWnd, HWND_TOP, x, y + h / 2, w / 2, h / 2, SWP_NOZORDER);
break;
}
I managed to correct this effect by inflating target rectangle by a calculated margin like this:
static RECT GetSystemMargin(IntPtr handle) {
HResult success = DwmGetWindowAttribute(handle, DwmApi.DWMWINDOWATTRIBUTE.DWMWA_EXTENDED_FRAME_BOUNDS,
out var withMargin, Marshal.SizeOf<RECT>());
if (!success.Succeeded) {
Debug.WriteLine($"DwmGetWindowAttribute: {success.GetException()}");
return new RECT();
}
if (!GetWindowRect(handle, out var noMargin)) {
Debug.WriteLine($"GetWindowRect: {new Win32Exception()}");
return new RECT();
}
return new RECT {
left = withMargin.left - noMargin.left,
top = withMargin.top - noMargin.top,
right = noMargin.right - withMargin.right,
bottom = noMargin.bottom - withMargin.bottom,
};
}
And then doing
RECT systemMargin = GetSystemMargin(this.Handle);
targetBounds.X -= systemMargin.left;
targetBounds.Y -= systemMargin.top;
targetBounds.Width += systemMargin.left + systemMargin.right;
targetBounds.Height += systemMargin.top + systemMargin.bottom;
That worked for all windows I could test it with, except Explorer windows, which I hardcoded to exclude. If I'd do that expansion on Explorer near the screen edge, window ends up spilling a large area past it to the adjacent monitor.
The default font size of windows XP/7/8/8.1 is 100%, but in windows 10 the default is to display text and items in 125%. That affects directly all the window sizes.
Go to settings, display and you will find a scroller, move it to 100% and everything should display the same way as it did in Windows 8/7/XP

how to get width - height of a controls within dialogbox

I had created a dialog with some controls -
IDD_DIALOG_EFFECTS DIALOGEX 0, 0, 168, 49
STYLE DS_SETFONT | WS_CHILD
FONT 8, "MS Sans Serif", 400, 0, 0x1
BEGIN
--- ---
--- ---
CTEXT "",3,200,120,60,60, WS_VISIBLE
END
In Header - file:
const int16 kItem = 3;
Now when I am trying to get the position and dimension of the control, it's not accurate.
// Retrieving the location and dimension of the control
RECT wRect_proxy;
GetWindowRect(GetDlgItem(hDlg, kItem), &wRect_proxy);
ScreenToClient (hDlg, (LPPOINT)&wRect_proxy);
ScreenToClient (hDlg, (LPPOINT)&(wRect_proxy.right));
// Output of the control as location and position that I am getting is:
wRect_proxy.left: 300 (Expected: 200)
wRect_proxy.top: 195 (Expected: 120)
wRect_proxy.right: 390 (Expected: 60)
wRect_proxy.bottom: 293 (Expected: 60)
I need to calculate width - height of the control. Seeking help ...
What you receive IS the height of the contro!
The RC file uses Dialog Base Units.
When the Dialog is created the specific font is used to find howmany Pixels are 1 DLU.
Internally MapDalogRect is used to convert the values from the RC file to the final number of Pixels.
Using MapDialogrect on CRect(0,0,4,8) gives you the base values of 1 DLU.
Now take the x-width multiply with 4 and divide by the "width" base units you just calculated. For the y-height multiply with 8 and divide by the
"height".
This can be easily done with MulDiv.
Thanks a Ton ... :)
As per your guidance and suggestion the snippet will be:
// Summarizing the code-snippet.
RECT wRect;
GetWindowRect(GetDlgItem(hDlg, kDProxyItem), &wRect);
ScreenToClient (hDlg, (LPPOINT)&wRect);
ScreenToClient (hDlg, (LPPOINT)&(wRect.right));
RECT pixel_rect;
pixel_rect.left = 0;
pixel_rect.top = 0;
pixel_rect.right = 4;
pixel_rect.bottom = 8;
bool b_check = MapDialogRect(hDlg, &pixel_rect);
LONG base_pix_width = pixel_rect.right;
LONG base_pix_height = pixel_rect.bottom;
// Calculating acctual X,Y coordinates with Width - Height of the Proxy Rectangle
RECT proxy_acc_dim;
proxy_acc_dim.left = (wRect.left * 4 / base_pix_width);
//or we can do the same by: MulDiv(wRect.left, 4, base_pix_width);
proxy_acc_dim.right = (wRect.right * 4 / base_pix_width) - proxy_acc_dim.left;
//or we can do the same by: MulDiv(wRect.right, 4, base_pix_width);
proxy_acc_dim.top = (wRect.top * 8 / base_pix_height);
//or we can do the same by: MulDiv(wRect.top, 8, base_pix_height);
proxy_acc_dim.bottom = (wRect.bottom * 8 / base_pix_height) - proxy_acc_dim.top;
//or we can do the same by: MulDiv(wRect.bottom, 8, base_pix_height);
proxy_acc_dim.left = proxy_rect.left;
proxy_acc_dim.top = proxy_rect.top;
proxy_acc_dim.right = proxy_rect.right - proxy_rect.left;
proxy_acc_dim.bottom = proxy_rect.bottom - proxy_rect.top;
It works fine. Hope it would be help full to others ...

How to identify specific object using JavaCV

I am trying to detect doctor's tools from endoscopy video using the following code
static void video_tracking(){
//read image
IplImage orgImg = cvLoadImage("C:/Users/Ioanna/Desktop/pic.png");
IplImage thresholdImage = hsvThreshold(orgImg);
cvSaveImage("hsvthreshold.jpg", thresholdImage);
Dimension position = getCoordinates(thresholdImage);
System.out.println("Dimension of original Image : " + thresholdImage.width() + " , " + thresholdImage.height());
System.out.println("Position of red spot : x : " + position.width + " , y : " + position.height);
}
static Dimension getCoordinates(IplImage thresholdImage) {
int posX = 0;
int posY = 0;
CvMoments moments = new CvMoments();
cvMoments(thresholdImage, moments, 1);
double momX10 = cvGetSpatialMoment(moments, 1, 0); // (x,y)
double momY01 = cvGetSpatialMoment(moments, 0, 1);// (x,y)
double area = cvGetCentralMoment(moments, 0, 0);
posX = (int) (momX10 / area);
posY = (int) (momY01 / area);
return new Dimension(posX, posY);
}
static IplImage hsvThreshold(IplImage orgImg) {
// Convert the image into an HSV image
IplImage imgHSV = cvCreateImage(cvGetSize(orgImg), 8, 3);
cvCvtColor(orgImg, imgHSV, CV_BGR2HSV);
//create a new image that will hold the threholded image
// 1- color = monochrome
IplImage imgThreshold = cvCreateImage(cvGetSize(orgImg), orgImg.depth(), 1);
//do the actual thresholding
cvInRangeS(imgHSV, cvScalar(13, 0, 0, 0), cvScalar(40, 117, 124, 88), imgThreshold);
cvReleaseImage(imgHSV);
cvSmooth(imgThreshold, imgThreshold, CV_MEDIAN, 13);
// save
return imgThreshold;
}
The input of the above code is a color image with 2 doctor's object and the output is a grayscale image that detect the tools. Sorry, but the system doesn't allow to upload the images.
The problem is I don't know how to find the position of 2 tools and draw a rectangle. Please can some one explain how to archive my objective using javacv/opencv?
It can be achieve using Haar Casacde files .Some of the bulit-In Haar files provided by google can found in opencv\data\haarcascades directory .These files are XML files generated by heavy training sections.Some of the sample haar files are used for face detection,ear detection etc.A sample project can be fount at here.You can generate your own haar cascade file for any purpose.one of the method for generate Haar cascade file can be found at here

find the white/ black pixels in specific region javacv

I have tried this code. 540 is the left most x value of the box,3 is left most y value of the box,262 - width ,23 -height of the region which I am going to calculate the ratio of the white/black pixels. What I really wanted to do is detect the number of white/black pixel ratio in a specific region.I have calculate the coordinates for each cell (regions which I am going to specified)and try with this code.But the error in counting.
Can I please have an idea about this issue please..
I am really stuck here with my final year project.
CvSize cvSize = cvSize(img.width(), img.height());
IplImage image = cvCreateImage(cvSize, IPL_DEPTH_8U, 1);
IplImage image2 = cvCreateImage(cvSize, IPL_DEPTH_8U, 3);
cvCvtColor(image2, image, CV_RGB2GRAY);
cvSetImageROI(image2, cvRect(540,3,262,23));
//IplImage image2 = cvCreateImage(cvSize, IPL_DEPTH_8U, 3);
//
//cvCvtColor(arg0, arg1, arg2)
// cvCvtColor(image2, image, CV_RGB2GRAY);
//cvThreshold(image, image, 128, 255, CV_THRESH_BINARY);
CvLineIterator iterator = new CvLineIterator();
double sum = 0, green_sum = 0, red_sum = 0;
CvPoint p2 = new CvPoint(802,3);
CvPoint p1 = new CvPoint(540,26);
int lineCount = cvInitLineIterator(image2, p1, p2, iterator, 8, 0 );
for (int i = 0; i < lineCount; i++) {
sum += iterator.ptr().get() & 0xFF;
}
System.out.println("sum................"+sum);
CV_NEXT_LINE_POINT(iterator);
}
}
it gave the result as sum................0.0
I have really stuck with this..can you please give any solution for this issue please
Move CV_NEXT_LINE_POINT(iterator); line inside the for loop. Then it should work.

Help please with CGBitmapContext and 16 bit images

I'd LOVE to know what I'm doing wrong here. I'm a bit of a newbie with CGImageRefs so any advice would help.
I'm trying to create a bitmap image that has as it's pixel values a weighted sum of the pixels from another bitmap, and both bitmaps are 16bits per channel. For some reason I had no trouble getting this to work with 8bit images but it fails miserably with 16bit. My guess is that I'm just not setting things up correctly. I've tried using CGFloats, floats and UInt16s as the data types but nothing has worked. The input image has no alpha channel. The output image I get looks liked colored snow.
relevant stuff from the header:
UInt16 *inBaseAddress;
UInt16 *outBaseAddress;
CGFloat inAlpha[5];
CGFloat inRed[5];
CGFloat inGreen[5];
CGFloat inBlue[5];
CGFloat alphaSum, redSum, greenSum, blueSum;
int shifts[5];
CGFloat weight[5];
CGFloat weightSum;
I create the context for the input bitmap (a CGImageRef created with CGImageSourceCreateImageAtIndex(source, 0, NULL)) using:
size_t width = CGImageGetWidth(inBitmap);
size_t height = CGImageGetHeight(inBitmap);
size_t bitmapBitsPerComponent = CGImageGetBitsPerComponent(inBitmap);
size_t bitmapBytesPerRow = (pixelsWide * 4 * bitmapBitsPerComponent / 8);
CGColorSpaceRef colorSpace = CGImageGetColorSpace(inImage);
CGBitmapInfo bitmapInfo = kCGBitmapByteOrderDefault | kCGImageAlphaNoneSkipLast;
CGContextRef inContext = CGBitmapContextCreate (NULL,width,height,bitmapBitsPerComponent,bitmapBytesPerRow,colorSpace,bitmapInfo);
The context for the output bitmap is created in the same way. I draw the inBitmap into the inContext using:
CGRect rect = {{0,0},{width,height}};
CGContextDrawImage(inContext, rect, inBitmap);
Then I initialize the inBaseAddress and outBaseAddress like so:
inBaseAddress = CGBitmapContextGetData(inContext);
outBaseAddress = CGBitmapContextGetData(outContext);
Then I fill the outBaseAddress with values from the inBaseAddress:
for (n = 0; n < 5; n++)
{
inRed[n] = inBaseAddress[inSpot + 0 + shifts[n]];
inGreen[n] = inBaseAddress[inSpot + 1 + shifts[n]];
inBlue[n] = inBaseAddress[inSpot + 2 + shifts[n]];
inAlpha[n] = inBaseAddress[inSpot + 3 + shifts[n]];
}
alphaSum = 0.0;
redSum = 0.0;
greenSum = 0.0;
blueSum = 0.0;
for (n = 0; n < 5; n++)
{
redSum += inRed[n] * weight[n];
greenSum += inGreen[n] * weight[n];
blueSum += inBlue[n] * weight[n];
alphaSum += inAlpha[n] * weight[n];
}
outBaseAddress[outSpot + 0] = (UInt16)roundf(redSum);
outBaseAddress[outSpot + 1] = (UInt16)roundf(greenSum);
outBaseAddress[outSpot + 2] = (UInt16)roundf(blueSum);
outBaseAddress[outSpot + 3] = (UInt16)roundf(alphaSum);
As a simple check I've tried:
outBaseAddress[outSpot + 0] = inBaseAddress[inSpot + 0];
outBaseAddress[outSpot + 1] = inBaseAddress[inSpot + 1];
outBaseAddress[outSpot + 2] = inBaseAddress[inSpot + 2];
outBaseAddress[outSpot + 3] = inBaseAddress[inSpot + 3];
which works and at least means that the contexts and pointers to the bitmap data are working.
Thanks for any input. This has been pretty frustrating since it worked just fine with 8bit images.
OK, I've got it figured out. I needed to set the bitmapInfo to kCGBitmapByteOrder16Little for the 16bit images and to kCGBitmapByteOrder32Little for the 8bit images. I'm a bit surprised by this actually as would have expected it to be the other way around (32Little for 16 bit and 16Little for 8bit).
I also needed to type def the pointers to the bitmaps as UInt8* and UInt16*. It also appears that I have to include an alpha channel in the bitmapContext. I'm not sure why but the context returned was always nil without it.
It sounds like a byte ordering problem
Have you checked that CGImageGetBitsPerComponent is returning 16? As a matter of style, if you're assuming you're creating a bitmap context with 16 bits per pixel (since you treat the data as UInt16*), you should set explicitly set size_t bitmapBitsPerComponent = 16.
What is your shifts array for? It seems like the most likely place for error, since it's affecting the address you're reading from, but you don't explain it at all. Are the values in shifts multiples of 16?

Resources