Using camera to analyze garage door status - c#

I got the idea to use images from my IP camera, to register if my garage door is open or closed (or maybe even somewhere in between).
I figured it would be simple to put some identifiable markers on the door, and then "read" their position programatic, but I have no experince in image processing, and therefore no idea what it's called.
After a lot of reading, my guess is that I need to use Emgu CV in some way (I'm coding in C#).
Can someone point me in the right direction to get started?
What is the right method for what I am trying to achieve? Blob tracking?

I know this is old but I happen to have done exactly this recently.
I have an old smartphone from which I can remotely enable the LED flash + take a picture and download it. I attached a shiny reflector on a specific location of the garage door and the smartphone is drilled to the wall.
I implemented in python. I download the picture over HTTP, and after a few attempts I identified where to crop the full picture. Then I compute the brightness, which tend to indicate a valid detection above 150 (it's usually 200 when the reflector is here, 130 when it's not but lights on, and 10 when the reflector is not here and lights are off).
def loadFromCam(url):
print("GET " + baseUrl + url)
return requests.get(baseUrl + url, timeout=(10,10))
def brightness(im):
stat = ImageStat.Stat(im)
return stat.rms[0]
def loadImage():
response = loadFromCam("cam/1/frame.jpg")
f = open(destination + 'frame.jpg', 'wb')
f.write(response.content)
f.close()
return Image.open(BytesIO(response.content))
def cropImage(img):
left = 365
top = 400
right = 410
bottom = 435
return img.crop((left, top, right, bottom))
def toggleLed():
loadFromCam("cam/1/led_toggle")
and then how it's used:
toggleLed()
time.sleep(0.1)
image = loadImage()
toggleLed()
crop = cropImage(image)
crop.save(destination + "crop.jpg")
print("brightness:", brightness(crop))
The result is two files (full picture and crop), and the brightness amount.
Note: I just started Python so this may be ugly or not the recommended practice

Related

How to figure out direction of text or page with tesseract

So I have been trying to figure this out for a whole day now. And I really hope someone will be able to help me out.
I am trying to write a software, that will process a PDF document. Processing means, deleting empty pages and rotating pages that have been scanned upside down.
Obviously I need some kind of OCR library here, so I went with Tesseract. Detecting empty pages was easy enough. But the Orientation property doesn't seem to work at all (EDIT: by not working I mean it always says "PageUp"). But from what I gathered so far, this should give me a hint to whether or not my page is upside down. Am I missing something? Maybe something that has to be included in the tessdata folder for this?
I also tried the approach of testing for GetMeanConfidence, flip the image and then compare the MeanConfidences, because in theory the page that wasn't upside down, should be easier to read. But the difference is so minimal, that I don't think this is reliable.
And I switched the language attribute of the TesseractEngine. I tried "eng", "deu", and "osd". All with the same result.
Bitmap image = new Bitmap(filepath);
var path = Path.GetDirectoryName(Assembly.GetExecutingAssembly().CodeBase);
path = Path.Combine(path, "tessdata");
path = path.Replace("file:\\", "");
var engine = new TesseractEngine(path, "osd", EngineMode.TesseractOnly);
using (var img = PixConverter.ToPix(image))
{
using (var page = engine.Process(img, PageSegMode.AutoOsd))
{
var pageIterator = page.AnalyseLayout();
pageIterator.Begin();
var pageProperties = pageIterator.GetProperties();
Console.WriteLine(pageProperties.Orientation.ToString() +" "+
pageProperties.TextLineOrder + " " + pageProperties.DeskewAngle + " " +
pageProperties.WritingDirection);
Console.WriteLine(page.GetMeanConfidence());
}
}
I expect an output that tells me if the page is upside down. So that I know if it has to be rotated or not. Performance doesn't matter!
I am also open for different approaches and libraries (as long as they're free).

Unity3d - 2 issues with Facebook Sharing in Window Phone

Everybody,I must say that I have post this question 3 times in Unity Community (include answer hub and its forum) but no one can solve it.
I use TakeScreenShot() function (it's in the InteractiveConsole example in FB SDK for Unity) to take a screenshot and post it to FB. But there are 2 problems appeared:
First: the screenshot that's captured is a gray blank like this: http://i7.minus.com/iXiHlCcSWaVfC.jpg
Second: No one can see my post except me although I set the photo to public.
How can I fix these problems?
Here is the code of TakeScreenShot() function:
private IEnumerator TakeScreenshot() {
yield return new WaitForEndOfFrame();
var width = Screen.width;
var height = Screen.height;
var tex = new Texture2D(width, height, TextureFormat.RGB24, false);
// Read screen contents into the texture
tex.ReadPixels(new Rect(0, 0, width, height), 0, 0);
tex.Apply();
byte[] screenshot = tex.EncodeToPNG();
var wwwForm = new WWWForm();
wwwForm.AddBinaryData("image", screenshot, "InteractiveConsole.png");
wwwForm.AddField("message", "herp derp. I did a thing! Did I do this right?");
FB.API("me/photos", Facebook.HttpMethod.POST, Callback, wwwForm);
Debug.Log("done");
}
I hope you solved your issues but I will answer anyways to your questions:
•First: the screenshot that's captured is a gray blank.
I think this works for Windows Phone only since very recently on Unity 4.5, update and try again.
Unity 4.5 Windows Phone Fixes
Grey Textures happen if you forget to call the Apply method. You will end up with a grey texture if forget to call. I see you are calling tex.Apply() but my guess is that you added it later and you may be seeing an old grey texture. Your code should work as it is. If you still get the grey Texture after updating to version 4.5 or later, try to wait a little time between the Apply and calling the EncodeToPNG(), maybe yield between those calls. Bear in mind that both are expensive operations.
•Second: No one can see my post except me although I set the photo to public.
That is because you have not go live (public) with you facebook app, during development only you will see you and your development team will see the messages. By the way fecebook will not approve hardcoded messages so even though this may work, and I know you based your code on facebook own smaples, you will need to allow the user to edit the message before posting.

Zxing qr code decode can't get it work

I've searched all the forum and I cannot find the answer (and this is my first post, so sorry for possible errors).
I've downloaded Zxing pack and I would like to get the qr code decoder work (in c#, a WPF application). The problem is that I get no error while compiling, and the application goes well (I take the input stream from kinect rgb camera) but it seems it does nothing.
I report some code (probably I've made some error...):
RGBLuminanceSource ls = new RGBLuminanceSource(bit, frame.Width,frame.Height);
Result result = new QRCodeReader().decode(new BinaryBitmap(new HybridBinarizer(ls)));
if (result != null)
Console.WriteLine("yahoo!");
else
Console.WriteLine("oh no");
with frame that is the frame captured by the kinect, and bit is the byte[] array that RGBLuminanceSource want as input, and I've made it by this:
byte[] bit= new byte[frame.PixelDataLength];
colorFrame.CopyPixelDataTo(bit);
What pass is that, when I put the paper with the qr code in front of the camera, it always return me the message "oh no", and I cannot figure out what I'm doing wrong.
As far as I know the image which you get from the kinect camera is flipped.
You have to flip it back before decoding.
You can find some more detail here:
http://zxingnet.codeplex.com/discussions/401772
In case someone stumbles upon this question, There are few things you can check.
Download the QRCodeDecoder sample from ZXing git and have it at ready
Save your Bitmap file to a folder location.
Check whether the saved Image decodes correctly from the QRCodeDecoder.
If you are using this for a QR Code scanner via the webcam or other video source, check whether you are converting the bitmap image in the correct pixel format.
hope this helps

How many USB cameras can be accessed by one PC

I am just wondering how many USB cameras can be accessed by one desktop PC? Is there any limit? I am planning to create my own Windows application (using .NET) to capture around 10 USB cameras that are connected to my desktop PC. Is this possible?
The problem is not how many you can discover. On a single USB bus, ~127 could be possible.
But, a USB bus can only transfer a limited amount of bytes per second. So if you want to use more then one, you have to calculate the amount of bandwidth you have for the video stream.
Example :
A USB bus normally can deliver realistically ~35 MB/s. 640*480*2 bytes per pixel => 614400 bytes per frame. #30 FPS this is ~17 MB/s, so you can use 2 cameras simultaneously with this setup.
If that Actually, see code for connect 5 cams in to one computer( processor core i3, 8gb ram!!!) you need connect all cameras in to usb ports only on you'r computer!!!
git hub link
a bit late sorry :)
What i found out is that a single USB card is limited by the USB bandwidth. but..
if you add USB cards on the PCI you can get more cameras but...
most vendors do not bother to alter the USB card address the computer see so you need to buy USB to PCI cards from different vendors and try your luck.
I had the same problem with firewire.
here is my code for python. (thank other programmers on stackoverflow)
# show multiple usb cameras
import os
import cv2
import threading
import time
import datetime
#font for image writing
font = cv2.FONT_HERSHEY_SIMPLEX
fontScale = 1
fontColor = (255,180,180)
lineType = 2
SaveImage = True # if true save images
duration = [100,100,100,10,10] # time between image saves in sec
IMAGESAVEPATH = "C:/tmp/pix" # path for camera to store image to
ShowText = True #Show text on image - text will be saved with the image
#camera thread. here me make a thread and its functions
class camThread(threading.Thread):
def __init__(self, previewName, camID):
threading.Thread.__init__(self)
self.previewName = previewName
self.camID = camID
def run(self):
print ("Starting " + self.previewName)
camPreview(self.previewName, self.camID)
#camera main loop - here we init the specific camera and start it then have a window to show the image and we store the image to the right directory
def camPreview(previewName, camID):
cv2.namedWindow(previewName)
cam = cv2.VideoCapture(camID) #start the camera (the cameras are numbered by the order they are connected to the computer)
if cam.isOpened(): # try to get the first frame
cam.set(3,4000) #this will bring the largest frame set
cam.set(4,4000)
cam.set(5,1) #fps
time.sleep(2)
cam.set(15, -1.0)
rval, frame = cam.read() #read the image
else:
rval = False
TStart = time.time() # time for next image
mpath = os.path.join(IMAGESAVEPATH, str(camID)) #make sure the directory we save in exists, otherwise make it
print("try to make dir ", mpath, " T " , time.time())
if not os.path.exists(mpath):
os.makedirs(mpath)
cv2.namedWindow(previewName, cv2.WINDOW_NORMAL)
while rval: #if we get an image
height, width, channels = frame.shape
if ShowText: # write text on the image
caption = str(camID) + " - " + str(height) + " " + str(width) + " "
cv2.putText(frame,str(caption),(20,20),font, fontScale, fontColor, lineType)
cv2.imshow(previewName, frame) # show image in its window
#cv2.resizeWindow(previewName, 1280,960) # resize all windows removed ofer
rval, frame = cam.read() #raed next image
key = cv2.waitKey(20)
if key == 27: # exit on ESC
print("key pressed ", camID)
break
TDiff = int(time.time() - TStart) # time difference from last image
if (SaveImage and TDiff > duration[camID]): # Save if time passed
file_name = os.path.join(mpath, "T{:%Y.%m.%d %H-%M-%S}.jpg".format(datetime.datetime.now())) # make file name string
cv2.imwrite(file_name, frame)
print("\rsaved to : ", file_name)
TStart = time.time() #reset time to next image
cv2.destroyWindow(previewName)
# Create 5 threads as follows
thread1 = camThread("Camera 1", 0)
thread2 = camThread("Camera 2", 1)
thread3 = camThread("Camera 3", 2)
thread4 = camThread("Camera 4", 3)
thread5 = camThread("Camera 5", 4)
thread1.start()
thread2.start()
thread3.start()
thread4.start()
thread5.start()
[Edited]
Actually, see this article which explains:
Get List of connected USB Devices
I'm not sure there is a maximum. I will check and post back if I find out.
[Further Edit]
Can't find a documented maximum. Theoretically the ManagementObjectCollection should be able to hold millions of objects in it. If you ran into problems (which I doubt with 10 devices), you could just preallocate the collection size upon instantiation.
I've just ran a test and I can pick up over 10 USB devices through a hub. You should be fine.
Maximum limit for usb devices connected to one host - 127. So, you can connect up to 100+ devices and they would work fine (100+ - because hub is also active device and have own address).
Possibly, you try to access first (already active) camera and program fails, because camera already locked?

Parsing large xml files to add new line between elements really slow

I have a scenario where I need to pull data out of a DB and write it out as xml. The problem is that the users want every element (DB Column) to be separated by a new line. The db table I am extracting has about 20,000 rows and has a lot of ntext columns (Table is about 3 Gig in size).
I am breaking the file up into 250 rows each so each file comes out to be around 14MB each. The problem is that the parsing is really really slow. In order to add a new line between each element/column I am adding some unique strings between each column coming out of the db so that I can use a Regex.Split function and append a new line to each item in that array.
I am sure that the slowness is user error / ignorance on my part as I live mostly in DBs, but I am not really sure what to do to try and speed up the parsing. Extracting the data as xml from the db is fast and writes rather quickly. But, introducing the parsing and adding a new line between each element has made each file write about 3 minutes per file.
Any suggestions on what I should be using in C# to parse and add the newline would be greatly appreciated.
As always I appreciate the input / comments I get on Stack.
Code I am using to parse the xml data:
//parsing the xml anywhere I see the string AddNewLine
public static void WriteFile(string xml,int fileNum)
{
string[] xmlArray = Regex.Split(xml, "AddNewLine");
string newXml = "";
//Getting filepath to write file out to
Connection filePath = new Connection();
string fileName = filePath.FilePath;
//foreach item in the array append carriage and new line
foreach(string xmlRow in xmlArray)
{
newXml = newXml + xmlRow + "\n\r\n";
}
//use StreamWriter to write file
using (StreamWriter sw = new StreamWriter(fileName + fileNum + ".xml"))
{
sw.Write(newXml);
}
//XmlDocument doc = new XmlDocument();
//doc.LoadXml(newXml);
//doc.Save(#"C:\TestFileWrite\PatentSchemaNew_" + fileNum + ".xml");
}
Example XML output where I would want a new line between each element:
<products>
<product>
<ProductID>1</ProductID>
<!--New Line-->
<Product>TestProduct1</Product>
<!--New Line-->
<ProductDescription>With the introduction of the LE820 Series, Sharp once again establishes its leadership in LCD and LED technology. In a monumental engineering breakthrough, Sharp’s proprietary QuadPixel Technology, a 4-color filter that adds yellow to the traditional RGB, enables more than a trillion colors to be displayed for the first time. A stunning new contemporary edge-light design with full-front glass proudly announces a new AQUOS direction for 2010. The proprietary AQUOS LED system comprised of the X-Gen LCD panel and UltraBrilliant LEDs enables an incredible dynamic contrast ratio of 5,000,000:1 and picture quality that is second to none. The LE820 series is very fully featured, including the addition of Netflix™ streaming video capability through the AQUOS Net™ service, along with the industry’s leading online support system, AQUOS Advantage Live. A built in media player allows for playback of music and photos via USB port.
QuadPixel Technology 4-Color Filter adds yellow to the traditional RGB sub-pixel components, enabling the display of more than a trillion colors.
Full HD 1080p (1920 x 1080) Resolution for the sharpest picture possible.
UltraBrilliant LED System includes a “double-dome” light amplifier lens and multi-fluorescents, enabling high brightness and color purity.
Full HD 1080p X-Gen LCD Panel with 10-bit processing is designed with advanced pixel control to minimize light leakage and wider aperture to let more light through.
120Hz Fine Motion Advanced for fast-motion picture quality.
Wide Viewing Angles (176°H x 176°W) Sharp's AQUOS® LCD TVs’ viewing angles are so wide, you can view the TV clearly from practically anywhere in the room.
High Brightness (450 cd/m2) AQUOS LCD TVs are very bright. You can put them virtually anywhere – even near windows, doors or other light sources – and the picture is still vivid.
AQUOS Net delivers streaming video with Netflix™, customized Internet content and live customer support via Ethernet, viewable in widget, full-screen or split-screen mode.
USB Media Player adds the convenience of viewing high-resolution photos and music on the TV.</ProductDescription>
<!--New Line-->
<ProductAccessories> What You'll Need
Add
Monster Cable MC BNDLF OL150F Bundle HDTV Performance Kit with Flat Panel Wall Bracket
Monster Cable HT700 8 Outlet Surge Protector
Monster's SurgeGuard™ protects components from harmful surges and...
$208.95
Get More Performance
Add
AudioQuest AQ Kit4 1-4ft. and 1-8ft. Black HDTV Performance Pack with HDMI Cables, Screen Cleaner & Mitt
Uncompressed digital signal for the highest quality picture and sound. One cable for video, audio and control. Two-way communication for expanded system control. Automatic display and source matching for resolution, format and aspect ratio. Computer and gaming compatibility. $79.75
Recommended Accessories
General Accessory
Add
Monster Cable ScreenClean 6oz. Ultimate Performance TV Screen Cleaner
Safe for use on your iPad, iPhone, iPod Touch, laptops, monitors, and TV screens Includes a high-tech reusable MicroFiber cloth that cleans screens without scratching Powerful cleaning solution removes dust, dirt, and oily fingerprints for ultimate clarity Advanced formula cleans without dripping, streaking, or staining like ordinary cleaners $13.94
Add
AudioQuest CleanScreen TV Screen Cleaning Kit
$19.75
Protection Plans
Add
TechShield TTL200S5 5-Year Service Warranty for LCD TVs $1,000-$2,000 (In-Home Service)
Parts and labor coverage with no deductibles No-lemon guarantee 50% value guarantee if you never use the warranty service $314.95
Add
TechShield TTL200S3 3-Year Service Warranty for LCD TVs $1,000-$2,000 (In-Home Service)
$157.95
Add
TechShield TTL200S4 4-Year Service Warranty for LCD TVs $1,000-$2,000 (In-Home Service)
$262.95
Add
TechShield TTL200S2 2-Year Service Warranty for LCD TVs $1,000-$2,000 (In-Home Service)
$104.95
Flat Panel Wall Mount - Fixed
Add
OmniMount OL150F Flat Panel Wall Bracket
Eco-friendly design and packaging Low mounting profile Includes universal rails and spacers for greater panel compatibility Small footprint provides ample room for power and A/V cutouts behind panel Lift n’ Lock™ allows you to easily attach your flat panel to the mount Sliding lateral on-wall adjustment Locking system secures panel to mount Installation template for simple and accurate mounting Includes end caps for a clean side view Includes complete hardware kit $99.95
Add
OmniMount NC200F Black Fixed Wall Mount for 37-63 inch Flat Panels
$129.95
Flat Panel Wall Mount - Tilt
Add
OmniMount NC200T Black Tilt Mount for 37-63 inch Flat Panels
Universal rails for greater panel compatibility Sliding lateral on-wall adjustment Locking bar works with padlock or screw End caps cover locking hardware and present a clean side view Installation template for simple and accurate mounting $179.95
Flat Panel Wall Mount - Cantilever/Articulating
Add
OmniMount UCL-X Platinum Wishbone Cantilever Mount Heavy Duty Dual Arm Double Stud
Tilt, pan and swivel for maximum viewing flexibility Weight capacity: 200 lbs Double-arm i-beam design for added strength Integrated cable management hides wires Lift and lock mounting system $279.88
Add
OmniMount NC125C Black Cantilever Mount for 37-52 inch Flat Panels
$299.95
Line Conditioner/Surge Protector
Add
Panamax PM8-GAV Surge Protector with Current Sense Control
8 Outlets (4 switched, 4 always on) Exclusive Protect or Disconnect circuitry Telephone line protection Cable and Satellite protection $59.89
Add
Monster Cable DL MDP 900 Monster Digital PowerCenter MDP 900 w/ Green Power and USB Charging
$74.77
HDMI Cable
Add
AudioQuest HDMI-X 2m (6.56 ft) HDMI Digital Audio Video Cable with Braided Jacket
Large 1.25% silver conductors Critical Twist Geometry Solid High-Density Polyethylene is used to minimize loss caused by insulation Uncompressed digital signal for the highest quality picture and sound $40.00
Add
Icarus ECB-HDM2 2m (6.56 ft) HDMI Digital Audio Video Cable
$16.95
Add
Monster Cable MC HDMIB 2m (6.56 ft.) HDMI Cable
$39.00
Component Video Cable
Add
Monster Cable MC 400CV-2m (6.56 ft.) Advanced Performance Component Video Cable
Get All the High Resolution Picture You Paid For
Your new DVD player, cable/satellite receiver, and TV might be more advanced... $49.00
Add
Monster Cable MC 400CV-1m (3.28 ft.) Advanced Performance Component Video Cable
$39.00
Add
AudioQuest YIQ-A 2m (6.6 ft) Component Video Cable
$44.75
General Accessory
Add
Monster Cable ScreenClean 6oz. Ultimate Performance TV Screen Cleaner
Safe for use on your iPad, iPhone, iPod Touch, laptops, monitors, and TV screens Includes a high-tech reusable MicroFiber cloth that cleans screens without scratching Powerful cleaning solution removes dust, dirt, and oily fingerprints for ultimate clarity Advanced formula cleans without dripping, streaking, or staining like ordinary cleaners $13.94
Add
AudioQuest CleanScreen TV Screen Cleaning Kit
$19.75</ProductAccessories>
<ProductFeatures>Detailed Specifications:
Basic Specifications
10-bit LCD Panel Yes
120HzFrameRate Yes
Aspect Ratio 16:09
Audio System 10W + 10W +15W (Subwoofer)
Backlight System Edge LED
Panel Type X-Gen LCD Panel
Pixel Resolution 1920 x 1080 (x4 sub-pixels) 8 million dots
Response Time 4ms
Tuning System ATSC / QAM / NTSC
Viewing Angles 176° H / 176° V Features
AQUOS Net Yes
AQUOS AdvantageSM Support Yes
AQUOS® Series Yes
Digital Still Picture Display Yes
Quattron quad pixel technology Yes
Included Accessories
Remote Control Yes
Table Stand Yes Power
Power Consumption AC (watts) 160W
Power Source 120 V, 60 Hz
Terminals
Audio Inputs (L/R) RCA X 2
Composite Video 1
Ethernet Input 1
HD Component 1
HDMI® 4
PC 1 (15-pin D-sub)
RS-232C 1
Weight & Dimensions Dimensions
Dimensions (wxhxd) (inches) 49-39/64" x 31-59/64" x 1-37/64
Dimensions with Stand(wxhxd) (inches) 49-39/64" x 33-57/64" x 13-25/64" Weight
Product Weight (lbs.) 66.1
Weight with Stand & Speakers (lbs.) 79.4</ProductFeatures>
<!--New Line-->
<CreatedDate>2011-03-13T12:59:54.627</CreatedDate>
<!--New Line-->
<LastModifiedDate>2011-03-13T12:59:54.627</LastModifiedDate>
<!--New Line-->
</product>
</products>
Thanks,
S
If I understand correctly the question and you have already AddNewLine separator in you input 14 MB XML files, possible you don't need load all file and split into parts at all. - Just read from input file line by line, replace AddNewLine text with new line in each line, where the separator exists and write modified line to new output file.
Following code will replace your AddNewLine text with \n\r\n in several orders faster than your function - less then 1 sec.
using (var streamOut = new StreamWriter(outputFileName)
{
using (var streamIn = new StreamReader(inputFileName)
{
while (!streamIn.EndOfStream)
{
string line = streamIn.ReadLine();
line = line.Replace("AddNewLine", "\n\r\n");
streamOut.WriteLine(line);
}
}
}
I think that you should investigate vtd-xml for at least three reasons:
Parsing performance and memory usage
Incremental update: DOM's problem is that it will construct a tree by taking apart the input document, then write the whole thing back out by concatnation. VTD-XML doesn't take apart the input doc, and the modification is by directly inserting the whitespace char (in your situation) into the docoument's byte representation. SAX and Pull will have the similar issue.
Support for xpath and random access.
Based on the info given above, I fully expect the performance to be below 1 sec for each file. What does your file look like? I would be glad to provide some sample code
Ok here is the code that does the white space insertion
using System;
using System.Text;
using System.Net;
using com.ximpleware;
public static void insertWS()
{
VTDGen vg = new VTDGen();
if (vg.parseFile("input.xml",false){
VTDNav vn = vg.getNav();
AutoPilot ap = new AutoPilot(vn);
XMLModifier xm = new XMLModifier(vn);
ap.selectXPath("/products/product/*");
while(ap.evalXPath()!=-1){
xm.insertAfterElement("\n");
}
xm.output("output.xml");
}
}
If I were you, I would abandon the string replace method and approach this from different angle. I would add the new lines as part of the xml when creating the xml and not after the fact. Something along the lines of:
void WriteXml(string xmlFileName, DataRowCollection rows)
{
var xmlSettings = new XmlWriterSettings { Indent = true };
using(StreamWriter stream = new StreamWriter(xmlFileName))
using(XmlWriter writer = XmlWriter.Create(stream, settings))
{
writer.WriteStartElement("products");
foreach(DataRow row in rows)
{
writer.WriteStartElement("product");
writer.WriteElementString("ProductID", row["ProductID"].ToString());
writer.Flush();
stream.WriteLine(); //insert new line
writer.WriteElementString("Product", row["Product"].ToString());
writer.Flush();
stream.WriteLine(); //insert new line
//repeat for rest of columns/elements
//...
writer.WriteEndElement(); //end product
}
writer.WriteEndElement(); //end products
}
}

Categories

Resources